真是膜拜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