Delphi String的散漫记录,真是知识无数,陷阱无数
真是膜拜Delphi C++ Builder编译器的作者们,要下多少苦功夫才能解决如此之多的问题,制造出一个神级作品给世人享用。另外以我的编程经验所能想到很麻烦但却是必须的还有两个地方,一个是Format函数,另一个是类型转换。有空看看FreePascal的源码可以略窥一二。其实我也是一个疯狂的政经爱好者,本来也不是很吊美国,觉得我们迟早各方面,包括最先进的科学技术,都能赶上的他们的。但是想想这些神级的工程师,包括Borland早期的和现在的Embarcadero,心里多少有些发怵。美国,虽然也有Facebook创始人这样不劳而获的人(至少真的不值这么多钱),但是更多的还是为了金钱而疯狂工作的工程师国家,这一点任正非的讲话里也提到过。虽然现在也还是走下坡路了,但是底子仍在。
PwideChar()强制转化的话会重新分配内存,这个内存是局部的,函数已结束内存就释放了。GetMem 和 StringToWideChar结合使用,函数结束也不会释放内存,但是这样需要在程序运行完毕手动释放内存了。
str1: String[6]; {指定大小不能超过 255} {多给了会被截断}
如果你的字符串长度不超过 255,完全可以用 ShortString,用法同 String,并且可以用在 Dll 中:
var
a: ShortString;
begin
SetLength(a, 64);
Delete(a, 1, 5);
end;
DLL里面是可以用String,只要传递的参数不是String就不用担心。参数可以用PChar,函数内部再转换
shorstring不是以null结尾的。
统计字符串长度时不包括 Null 结束字节.
用FastMM吧,不用DLL也可以实现DLL和EXE传递字符串了,下载网址
http://fastmm.sourceforge.net/
Dephi 2006里的内存管理器已经是 FastMM 了
开始我也觉得迷惑,后来打开 GetMem.inc 一看就什么都明白了:)(里面的代码就是FastMM,作者就是:Pierre le Riche)
至于怎么用可以看Delphi自带例子:
Demos\DelphiWin32\VCLWin32\MemMgr\SimpleShareMem
在主程序和DLL的项目引用第一行加上: SimpleShareMem, 就可以了
{在没有给 str 赋值以前, 既然声明了, 就有了指针地址(@str):}
ShowMessage(IntToStr(Integer(@str))); {1244652; 这是在栈中的 str 的指针地址}
{但现在还没有分配真正储存字符串内存}
ShowMessage(IntToStr(Integer(str))); {0; 0 就是 null}
{通过实际地址获取字符串, 其中的 pc 是前面定义的字符指针}
pc := PChar(Integer(str));
ShowMessage(pc); {Delphi}
A := 'Delphi';
//此时A的引用计数是-1,原因是'字符串'存储在静态数据区,
编译的时候地址就定了,属于常量~也就是说,它是不能动态地释放的;
{向左偏移 4 个字节就是字符串长度的位置, 读出它来(肯定是5):}
pint := PInteger(Integer(str) - 4);
ShowMessage(IntToStr(pint^)); {5}
{向左偏移 8 个字节就是字符串的引用计数, 读出它来(肯定是3):}
pint := PInteger(Integer(str) - 8);
ShowMessage(IntToStr(pint^)); {3}
//字符串 < > 字符数组
var
arr: array[0..5] of Char;
str: string;
begin
{可以把字符数组直接赋给字符串变量}
str := arr;
{但不能把一个字符串变量赋给字符数组}
//arr := str; {错误; 这需要用其他手段实现, 譬如复制或移动内存}
{其实字符串内部也是包含了一个字符数组, 所以能索引访问, 不过它的索引起始于 1}
ShowMessage(str[1]); {D}
end;
//字符数组 > 字符指针
var
arr: array[0..6] of Char;
p: PChar;
begin
arr := 'Delphi';
{如果直接把字符数组给字符指针, 结果不保险, 因为字符指针要找空字符(#0)结束}
{把数组的最后一个元素给 #0 就可以了}
arr[Length(arr)-1] := #0;
p := arr;
ShowMessage(p); {Delphi}
{假如把 #0 给到中间会怎样?}
arr[3] := #0;
p := arr;
ShowMessage(p); {Del; 给截断了}
end;
如果自己调用api,最快的方法是用pchar转换,保证最后一个字节是null。
获取所有汉字与 Unicode 的对照表
var
w: WideString;
i: Integer;
s: string;
List: TStringList;
begin
List := TStringList.Create;
for i := $4e00 to $9fa5 do
begin
s := #36 + IntToHex(i,4); {#36 是 $ 字符}
w := WideChar(i);
List.Add(s + '=' + w);
end;
List.SaveToFile('c:\temp\Unicode-Hz.txt');
List.Free;
end;
百度上还发现一奇技淫巧:Alt + X 组合键,MS Word 也会将光标前面的字符同其十六进制的四位 Unicode 编码进行互相转换。
似乎可以拿这个做密码啊,神仙都没法知道。
n1 := lstrlen(p);
n2 := lstrlen(buf);
n1 := lstrlenA('Delphi 的魅力');
n2 := lstrlenW('Delphi 的魅力');
ExtractStrings 函数就是, 譬如:
var
str: string;
num: Integer;
List: TStrings;
begin
str := 'e,1|w,2|s,3|n,4|v,5|';
List := TStringList.Create;
num := ExtractStrings(['|'], [], PChar(str), List);
ShowMessage(IntToStr(num)); {num 是分隔符的个数}
ShowMessage(List.Text); {List 是分割后的列表}
List.Free;
end;
lstrcpyn - 复制字符串, 同时指定要复制的长度
lstrcpy - 复制字符串
lstrcat - 合并字符串
IsCharAlphaNumeric - 是否是个文字(字母或数字)
IsCharAlpha - 是否是个字母
c := #19975; {万}
c := #$4E07; {万}
把字符串复制到剪贴板
uses Clipbrd;
Clipboard.SetTextBuf(PChar(str));
Delphi字符串、PChar与字符数组之间的转换
设有以下三个变量:
var
s:string;
p:pchar;
a:array[1..20] of char;
那么三者之间的转换如下:
1、字符串到PChar
p:=PChar(s);
2、PChar到字符串
s:=p;
3、PChar到字符数组
StrCopy(@a,p);
4、字符数组到PChar
PChar(@a);
5、字符串与字符数组之间的转换就只有通过PChar来中转了。例如下面这个例子:
procedure TForm1.btn1Click(Sender: TObject);
var
str:array[1..10] of char;
begin
StrCopy(@str,PChar(mmo1.Text));
mmo2.Text:=PChar(@str);
end
两行代码的前后位置对调一下 ,运行结果就不同了
是 Delphi 对字符串优化所造成的结果(Delphi 的 copy-on-write 技术)
AnsiString 可以直接当内存来使用,它不只可以存放字符,而是可以存放任何东西,你甚至可以将一个图片的数据存入 AnsiString 的内存块中。
Length 函数对于 ShortString 和 AnsiString 来说返回的是它们所存放的字符串的字节数,而不是字符数。
Length 函数对于 WideString 来说,返回的就是字符数,而不是字节数
WideString 没有引用计数。其实 WideString 是为了方便使用 COM 而产生的,也就是 BSTR 字符串。
UniodeString,增加了 codePage 和 elemSize 域。
PStrRec = ^StrRec;
StrRec = packed record
codePage: Word; // 代码页:Unicode、UTF-8、UTF-16、GB2312
elemSize: Word; // 元素大小:一字符占几个字节
refCnt: Longint; // 引用计数:字符串被几个字符串变量使用
length: Longint; // 字符串长度:字节数
end;
在 system 单元中还定义了 UTF8String 和 UCS4String 类型的字符串,定义如下:
UTF8String = type AnsiString(65001);
UCS4String = array of UCS4Char; { UCS4Char = type LongWord; }
RawByteString = type AnsiString($ffff);
这种类型的变量在接收任何格式的字符串时,都会保持源字符串的内存格式,不做任何改动。
var
Str: String;
P: PCardinal;
X: PWord;
begin
Memo1.Clear;
Str:=Self.ClassName; { TForm3 }
Memo1.Lines.Add(Str);
P := PCardinal(Str);
Dec(P); { 向前移动 4 个字节 }
Memo1.Lines.Add(IntToStr(P^)); { 结果 6 字符串长度 }
Dec(P); { 再向前移动 4 个字节 }
Memo1.Lines.Add(IntToStr(P^)); { 结果 1 引用计数 }
X:=PWord(Integer(P)-2); { 再向前移动 2 个字节 }
Memo1.Lines.Add(IntToStr(X^)); { 结果 2 字符宽度 }
X:=PWord(Integer(X)-2); { 再向前移动 2 个字节 }
Memo1.Lines.Add(IntToStr(X^)); { 结果 1200 UTF-16 代码页注册为代码页 1200 }
X^:=60001; {字符编码居然可以改变}
end;
1200—UCS-2LE Unicode 小端序
1201—UCS-2BE Unicode 大端序
65000—UTF-7 Unicode
65001—UTF-8 Unicode
不同的厂商对同一个字符集编码使用各自不同的名称:UTF-8在IBM称作代码页1208,在微软称作代码页65001,在SAP称作代码页4110.
微软在Windows操作系统没有转向UTF-16作为内码实现之前(也就是在Windows 2000之前),针对不同的使用地区与国家,定义了一系列的支持不同语言字符集的代码页,被称作"Windows(或ANSI)代码页"。代表性的是实现了ISO-8859-1的代码页1252.
Windows-1252与ISO-8859-1并不完全一致。ISO-8859-1在0x80-0x9F范围的控制字符,在Windows-1252中被可打印字符取代。由于在web网页中,ASCII控制字符不起作用,所以网页一般用Windows-1252代码页标记替代ISO-8859-1标记。
chcp命令带一个整数参数,则改变命令行窗口的当前代码页为参数所指定。
最牛的一篇对String的解释文章:
http://www.cnblogs.com/PocketZ/archive/2013/03/26/2983583.html
Delphi String的散漫记录,真是知识无数,陷阱无数的更多相关文章
- Delphi String 常用字串符处理函数
Delphi 在面对跨平台开发,程序语言也改进不少,不过有些改进,让原本 Delphi 开发者有些不适应,最显注的就是字串处理函数了,原本 Pascal 语言字串起始由 1 开始,几乎是它的经典了,新 ...
- delphi string.split 按照任意字符串分割语句
delphi string.split 按照任意字符串分割语句 1.就是把一个指定的字符串用指定的分割符号分割成多个子串,放入一个 TStringList 中 function ExtractStri ...
- Delphi 编写DLL动态链接库文件的知识
一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...
- Delphi 编写DLL动态链接库文件的知识和样例(有详细步骤,很清楚)
一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...
- delphi string,pchar,char的比较
来自:http://blog.163.com/kat_/blog/static/189284269201152513331999/ ---------------------------------- ...
- String、StringBuffer、StringBuidler 知识整理
String.StringBuffer.StringBuidler.这三个家伙,大家都不陌生,肯定也都会用.三者异同大家都能说出来,但是其根本原因是什么呢?带着下面问题,学习一下. 第一.String ...
- 我是这样记录javascript知识的------Day31
在陆续研究了几个javascript的几个小应用后,也算对javascript有了更深一点的认识,头脑中大约都有些印象,总体上说却有些模糊,这时.我知道,是时候看看w3cshool的这部分介绍了. 没 ...
- DELPHI 通用的数据记录复制过程
//表名,关键字段名,单条内容的SQL语句,产生新记录的值 function Tfrmdmmain.CopyTbale(const tablename, fileldname, swhere, new ...
- Harry and magic string HDU - 5157 记录不相交的回文串对数
题意: 记录不相交的回文串对数 题解: 正着反着都来一遍回文树 用sum1[i] 表示到 i 位置,出现的回文串个数的前缀和 sun2[i]表示反着的个数 ans+=sum1[i-1]*sum2[i] ...
随机推荐
- Xamarin XAML语言教程Xamarin.Forms中活动指示器的显示隐藏
Xamarin XAML语言教程Xamarin.Forms中活动指示器的显示隐藏 开发者除了可以在XAML中使用IsRunning属性控制指示器的显示隐藏外,还可以在代码隐藏文件中使用IsRunnin ...
- Oracle SID爆破工具SidGuess
Oracle SID爆破工具SidGuess 在Oracle中,SID是System IDentifier的缩写.SID是一个数据库的唯一标识符.当用户希望远程连接Oracle数据库时,则需要知道 ...
- SecureCRT双击Tab快速复制Session
- Docking For WPF–AvalonDock
桌面程序的应用,不可避免的就会用到大量的布局控件,之前的一个项目也想过去做类似于Visual Studio的那种灵活的布局控件,也就是界面上的控件能够实现拖拽放置.隐藏.窗口化等一系列的操作,但由于开 ...
- 【原创】Android View框架总结(三)View工作原理
测量/布局/绘制顺序 如何引起View的测量/布局/绘制? PerformTraversales() ViewRoot View工作基本流程 MeasureSpec SpecMode Measure ...
- 手动编译高速扫描器MasScan
常见的端口扫描器有NMAP,ZMAP,superScan等,我们使用后各有千秋,ZMAP号称44分钟扫全球ip,那么有没有比ZMAP更快的端口扫描器呢,今天我们来研究下masscan,这款扫描器号称3 ...
- MAC - 命令行中用sublime打开指定文件,使用ln命令建立软链接
眼下sublime是mac下最好的文本编辑软件.常常要使用它打开一些文件,比如html,js,txt,json等文件,可是sublime2默认不支持在命令行下调用.经过研究发现能够用建立软连接的方式调 ...
- Solidworks如何绘制螺纹
1 随便画一个圆柱 2 在原来的地方画一个一摸一样的圆(草图2) 3 在特征选项卡中点击曲线-螺旋线/涡状线 4 设置螺距和圈数,画螺旋线 5 建立一个基准面,第一参考是点,第二参考是 ...
- mongodb分片片键的选择(持续更新中)
首先要了解项目的情况,检查使用情况 对集合进行分片时,要选择一个或者两个字段拆分数据,这个键叫做片键 一旦拥有对个分片,在修改片键几乎是不肯能的事情,因此选择合适的片键是非常重要的. 对集合分片之前要 ...
- vuex mapGetters
1.vuex 配置 //vuex的配置 //注意Store是大写 const store = new Vuex.Store({ //数据保存 state: { show: false, count: ...