zoukankan      html  css  js  c++  java
  • string、AnsiString、WideString

    Delphi 的字符及字符串[1] - string、AnsiString、WideString、String[n]、ShortString

    //最常用的 string

    var
    str: string;  {定义}
    begin
    str := '万一'; {赋值}
    ShowMessage(IntToStr(Length(str))); {长度是: 4}
    end;

    //长字符串 AnsiString; 在当前版本(2007)中的默认状态下, String 就是 AnsiString

    var
    str: AnsiString;
    begin
    str := '万一';
    ShowMessage(IntToStr (Length(str))); {长度是: 4}
    end;

    //宽字符串 WideString (效率不及 AnsiString)

    var
    str: WideString;
    begin
    str := '万一';
    ShowMessage(IntToStr (Length(str))); {长度是: 2}
    end;

    //定长字符串

    var str1: String[6]; {指定大小不能超过 255}
    str2: String[100];
    begin
    {少给了也会占那些内存}
    str1 := '万一';
    ShowMessage(str1);          {万 一}
    ShowMessage(IntToStr(Length(str1))); {4; 这是字符串的长度}
    ShowMessage (IntToStr(SizeOf(str1))); {7; 这是占内存大小}
    {多给了会被截断}
    str1 := '万一的 Delphi 博客';
    ShowMessage(str1);          {万一的}
    ShowMessage(IntToStr (Length(str1))); {6; 这是实际保存的字符串长度}
    ShowMessage(IntToStr(SizeOf(str1))); {7; 这是占内存大小}
    {问题: 不是声明大小为 6 吗? 怎么 SizeOf 是 7 ? }
    {因为定长字符串会 多出一个首字节来记忆字符串的实际长度}
    {举例说明, 如果给 str2 按如下赋值, 那它的首字节 (sstr2[0])肯定储存着字符 'A'}
    str2 := 'iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii'; {65个}
    ShowMessage(str2[0]);        {A}
    ShowMessage(IntToStr(Ord(str2[0]))); {65s; 这是 'A' 在 ASCII 序列中的序号, 用的就是它}
    {那以后可以用 Ord(str2[0]) 来代替 Length 判 断字符串的长度吗? }
    {对定长字符串是可以的; 不但能读取, 还可以像 SetLength 一样设置}
    end;

    //ShortString; 它相当于 String[255]

    var
    str: ShortString;
    begin
    str := '万一的 Delphi 博客';
    ShowMessage(str);          {万一的 Delphi 博客}
    ShowMessage(IntToStr(SizeOf (str))); {256; 这是大小}
    ShowMessage(IntToStr(Length(str))); {18 ; 这是实际长度}
    ShowMessage(IntToStr(Ord(str[0]))); {18 ; 这是从首字节中取出的长度}
    end;

    Delphi的字符及字符串[2] - Char、AnsiChar、WideChar、PChar、PAnsiChar、PWideChar

     

    //单字符 Char、AnsiChar (在目前版本(2007)中, 它们是一回事, 只有 1 字节大小)var
    c: Char; {Char 类型的取值范围是: #0..#255, 用十六进制表示是: #$0..#$FF}
    begin
    { 用十进制方式赋值:}
    c := #65;
    ShowMessage(c); {A}
    {用十六进制方式赋值:}
    c := #$41;
    ShowMessage(c); {A}
    {用 Chr 函数代替 # 符号}
    c := Chr(65);
    ShowMessage(c); {A}
    c := Chr($41);
    ShowMessage(c); {A}
    {Char 长度当然会是 1}
    ShowMessage(IntToStr(Length(c))); {1}
    {Char、AnsiChar 允许这样方便地赋值(也就是 和 1 字节长度的字符串是兼容的):}
    c := 'B';
    ShowMessage(c); {B}
    end;
    //UniCode 字符 WideChar; 和 AnsiChar 不同, WideChar 是占 2 字节大 小.var
    c: WideChar; {WideChar 的取值范围是: #0..#65535, 用十六进制表示是: #$0..#$FFFF}
    begin
    {WideChar 兼容了 AnsiChar 的 #0..#255; 但占用了 2 字节大小}
    c := #65;
    ShowMessage(c); {A}
    ShowMessage(IntToStr(Length(c))); {1; 这是字符长度 }
    ShowMessage(IntToStr(SizeOf(c))); {2; 但占用 2 个字节}
    {用十六进制赋值}
    c := #$4E07;
    ShowMessage(c); {万}
    ShowMessage(IntToStr(Length(c))); {1; 这是字符长度 }
    ShowMessage(IntToStr(SizeOf(c))); {2; 但占用 2 个字节}
    {用十进制赋值}
    c := #19975;
    ShowMessage(c); {万}
    {如果不超出 #255 的范围是可以直接赋值的}
    c := 'B';
    ShowMessage(c); {万}
    {这样不行}
    //c := '万'; {这是 Delphi 的支持问题, 估 计 Delphi 2008 应该可以解决}
    {可以这样变通一下:}
    c := WideString('万')[1];
    ShowMessage(c); {万}
    {用 WideChar 的方式显示我的名字}
    ShowMessage(#19975#19968);   {万一}
    ShowMessage(#19975 + #19968); {万一}
    ShowMessage(#$4e07#$4e00);  {万 一}
    end;
    //字符指针 PChar、PAnsiChar; 在当前版本(2007)中它们没有区别.var
    p: PChar;
    str: string;
    begin
    {可以给 PChar 直接赋予字符串常量}
    p := ' 万一';
    ShowMessage(p);          {万一}
    ShowMessage(IntToStr(Length(p))); {4}
    {给变量值需要转换}
    str := '万一的 Delphi 博客';
    p := PChar(str); {转换} 
    ShowMessage(p);          {万一的 Delphi 博客}
    ShowMessage(IntToStr (Length(p))); {18}
    end;
    //宽字符指针 PWideCharvar
    p: PWideChar;
    str: WideString; {注意这里不是 String}
    begin
    {可以给 PWideChar 直接赋予字符串常 量}
    p := '万一';
    ShowMessage(p);          {万一}
    ShowMessage (IntToStr(Length(p))); {2}
    {给变量值需要转换}
    str := '万一的 Delphi 博客';
    p := PWideChar(str); {转换}
    ShowMessage(p);          {万一的 Delphi 博客}
    ShowMessage(IntToStr(Length(p))); {13}
    end;//
    唉~: 代码着色在这里又出现问题, 不过现在没心情修改了, 以后再说吧.

    //String 的指针地址及实际的内存地址
    var
    str: string;
    pstr: PString;
    pc: PChar;
    begin
    {在没有给 str 赋值以前, 既然声明了, 就有了指针地址 (@str):}
    ShowMessage(IntToStr(Integer(@str))); {1244652; 这是在栈中的 str 的指针地址} 
    {但现在还没有分配真正储存字符串内存}
    ShowMessage(IntToStr(Integer(str))); {0; 0 就是 null}
    str := 'Delphi';
    {一旦赋值后...}
    ShowMessage(IntToStr(Integer (@str))); {1244652; 这是在栈中的 str 的指针地址}
    ShowMessage(IntToStr(Integer(str)));  {4580800; 这是在堆中的 str 的实际地址}
    {通过指针地址获取字符串, 其中的 pstr 是前面定义 的字符串指针}
    pstr := @str;
    ShowMessage(pstr^); {Delphi}
    {通过实际地址获取字 符串, 其中的 pc 是前面定义的字符指针}
    pc := PChar(Integer(str));
    ShowMessage(pc);   {Delphi}
    end;
    一个字符串(AnsiString 或 String, 譬如是 "Form1" )在内 存中是这样储存的:

     

                    F o r m 1  

     

    黄色区域是真正存字符串的位置, 前面说的字符串所在的内存地址, 就是本例中的 "F" 所 在的位置;

    蓝色的四个字节储存一个 Integer 值, 表示字符串的长度;

    最后红色的一个字节储存一个空字符(#0), 表示字符串的结束, 同时也是为了和 Windows 的 null 结 束的字符串兼容;

    绿色的四个字节也是一个 Integer 值, 表示该字符串被引用的次数(也就是有几个字符串的指针指向 它).

    还是看例子吧:var
    str,s1,s2: string;
    pint: PInteger;
    begin
    str := Self.Text; {把窗体标题给它吧; 现在 str 指向了窗体标题所在的内存位置}
    s1 := str;     {给 s1 赋值}
    s2 := str;    {给 s2 赋值; 现在窗体标题已经有了 str、s1、s2 三个引 用}
    {str、s1、s2 的指针肯定不一样; 但现在指向内存的同一个位置, 测试:}
    ShowMessage (IntToStr(Integer(str))); {15190384}
    ShowMessage(IntToStr(Integer(s1))); {15190384}
    ShowMessage(IntToStr(Integer(s2))); {15190384}
    {向左偏移 4 个字节就是字符串长度的位 置, 读出它来(肯定是5):}
    pint := PInteger(Integer(str) - 4);
    ShowMessage(IntToStr (pint^));   {5}
    {向左偏移 8 个字节就是字符串的引用计数, 读出它来(肯定是3):}
    pint := PInteger(Integer(str) - 8);
    ShowMessage(IntToStr(pint^));   {3}
    end;
    当某段字符串内存的引用计数为 0 时, Delphi 就会自动释放它; 这也是字符串不需要手 动释放的原因.

    我在测试时发现: 所有常量和非全局的变量的引用计数一直是 "-1".

    //字符串与字符数组var
    arr: array[0..5] of Char;
    str: string;
    begin
    {可以把字符串常量直接赋给字符数组; 但超界不行}
    arr := 'Delphi';
    ShowMessage(arr); {Delphi}
    {可以把字符数组直接赋给字符串变量}
    str := arr;
    ShowMessage(str); {Delphi}
    {但不能把一个字符串变量赋给字符数组}
    //arr := str;    {错误}
    {其实字符串内部也是包含了一个字符数组, 所以能索引访问, 不过它的索引起始于 1} 
    ShowMessage(str[1]); {D}
    ShowMessage(arr[0]); {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;

    
    //字符串常量 > 字符数
    
    组常量 
    const
    arr1: array[0..5] of Char = 'Delphi';
    arr2: array[0..5] of AnsiChar = AnsiString('Delphi');
    begin
    ShowMessage(arr1[0]); {D}
    ShowMessage (arr2[0]); {D}
    end;
    
    
    Windows API 中的字符串对应这 Delphi 的 PChar(PAnsiChar); 在 API 中使用 Delphi 的字符串还 是比较灵活的.
    先说赋值://赋值方法1: 给直接量
    begin
     SetWindowText(Handle, '新标题');
    end;
    //赋值方法2: 定义它要的类型
    var
     p: PChar;
    begin
     p := '新标题';
     SetWindowText(Handle, p);
    end;
    //赋值方法3: 转换成它要的类型
    var
     str: string;
    begin
     str := '新标题';
     SetWindowText(Handle, PChar(str));
    end;
    //赋值方法4: 用字符数组
    var
     arr: array[0..255] of Char;
    begin
     arr := '新标题';
     SetWindowText(Handle, arr);
    end;
    再说取值://取值方法1: 用字符数组(经常被称作"缓冲区")
    var
     arr: array[0..254] of Char;
    begin
     GetWindowText(Handle, arr, 255);
     ShowMessage(arr); {Form1}
    end;
    //取值方法2: 使用 GetMem 给 PChar 分配内存
    var
     p: PChar;
    begin
     GetMem(p, 255); {分配内存}
     GetWindowText(Handle, p, 255);
     ShowMessage(p); {Form1}
     FreeMem(p);   {释放内存}
    end;
    //取值方法3: 用 GlobalAlloc 分配全局内存(比 GetMem 慢)
    var
     p: HGLOBAL;
    begin
     p := GlobalAlloc(0, 255); {参数一给 0 或 GMEM_FIXED 表示分配的是固定内存}
     GetWindowText(Handle, PChar(p), 255);
     ShowMessage(PChar(p)); {Form1}
     GlobalFree(p);     {释放内存}
    end;
    //取值方法4: 直接使用 string; 需要先 SetLength, 然后再去除空白:
    var
     str: string;
    begin
     SetLength(str, 255); {先设定 str 的长度}
     GetWindowText(Handle, PChar(str), 255);
     {但此时 str 的长度是 255 啊!}
     str := PChar(str); {这样可以得到实际长度的字符串}
     ShowMessage(str); {Form1}
    end;
    定长字符串不是 #0 结束的, 和 API 不好兼容, 一般不用于 API 中. c
    Delphi的字符及字符串[6] - Char(AnsiChar)、WideChar与其编码的相互转换
    //Char 类型与其编码值的转换:
    var
     b: Byte;
     c: Char;
    begin
     b := Ord('A');  {返回: 65}
     b := Ord(#65);  {返回: 65}
     b := Ord($41);  {返回: 65}
     b := Ord(#$41); {返回: 65}
     b := Byte('A'); {返回: 65}
     b := Byte(#65); {返回: 65}
     b := Byte($41); {返回: 65}
     b := Byte(#$41); {返回: 65}
     c := Chr(65);  {返回: A }
     c := Chr($41);  {返回: A }
     c := Char(65);  {返回: A }
     c := Char($41); {返回: A }
    end;

    //WideChar 类型与其编码值的转换; 汉字的 UniCode 编码范围是: $4E00..$9FA5
    var
     w : Word;
     c : WideChar;
     ws: WideString;
     s : string;
    begin
     {准备工作}
     ws := '万一';
     c := ws[1];
    //ShowMessage(c); {万}
     {从汉字到 UniCode 编码}
     w := Ord(c);         {返回十进制数    : 19975}
     w := Word(c);         {返回十进制数    : 19975}
     s := Format('%.4x',[Ord(c)]); {返回十六进制的字符串: 4E07 }
     s := IntToHex(Ord(c), 4);   {返回十六进制的字符串: 4E07 }
     {从 UniCode 编码到汉字}
     c := #19975;      {万}
     c := #$4E07;      {万}
     c := #$4e07;      {万}
     c := WideChar(19975); {万}
     c := WideChar($4E07); {万}
    end;


  • 相关阅读:
    9.1做JS的题目(2)
    9.1做JS的题目
    8.31做JS的题目
    8.30做JS的题目
    扫码跳转微信小程序(服务端微信API生成二维码)
    扫码跳转微信小程序(微信公众平台配置测试二维码)
    项目配置:maven下载与配置、tomcat下载与配置
    Java基础:常用工具_API
    Java基础: 抽象类、接口、final关键字、static关键字
    java基础: 封装、继承、多态
  • 原文地址:https://www.cnblogs.com/luckForever/p/7254549.html
Copyright © 2011-2022 走看看