真是膜拜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
|
请发表评论