• Delphi7中 string, AnsiString, Utf8String,WideString的区别分析


    Windows系统上的 Notepad.exe 打开文件后,点击“文件”菜单中的“另存为”命令,会跳出一个对话框,在最底部有一个“编码”的下拉条。
    里面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-8。
    1)ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。
    2)Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。
    3)Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。
    4)UTF-8编码,也就是上一节谈到的编码方法。

    缺省的编译选项下,编译器认为String就是AnsiString字符串(可以使用$H编译开关来进行修改)。


    AnsiString 这是Pascal缺省的字符串类型,它由AnsiChar 字符组成,其长度没有限制,同时与null结束的字符串相兼容,它的内存和ANSI编码格式的TXT文件的内存一样,AnsiString可能是全部都是ASCII字符,也可能包含中文字符。
    如果是在繁体中文windows系统上,可能包含繁体中文字符,如果是简体中文系统,则为GB2312编码,如果是繁体中文系统,则为BIG 5码。
    WideString功能上类似于AnsiString,但它是由WideChar字符(UniCode字符集)组成的。引入这种类型,主要是为了支持OLE编程。而且还有一个实用的功能,就是当一个字符串是中英文字符混杂时,能够准确计数字符数,并可分别访问其中每一个中文字符或英文字符,如果一个AnsiString中含有中英文字符时,就不容易确定字符数,也无法准确访问其中的每一个字符。AnisString字符串的每一个字节都不为零,但WideString的内存字节可能为0。AnsiString内存字节中,有可能一个字节代表一个字符,也可能两个字节代表一个字符,WideString全部是两个字节代表一个字符。

    可以将一个WideString赋给一个AnsiString,也可以将一个AnsiString赋给一个WideString,在赋值过程中将发生编码转换,如果一个WideString中的Unicode字符在ANSI字符集编码范围之外,则该Unicode字符被转为? (0x3F),所以就会出现拷贝一些阿拉伯字符串到文本框中后变成一串?的情况。

    Unicode编码则是采用双字节16位来进行编号,可编65536字符,基本上包含了世界上所有的语言字符,它也就成为了全世界一种通用的编码,而且用十六进制4位表示一个编码,非常简结直观,为大多数开发者所接受。


    AnsiString(或长字符串)类型是在Delphi2.0开始引入的,因为Delphi 1.0的用户特别需要一个容易使用而且没有255个字符限制的字符串类型,而AnsiString正好能满足这些要求。 虽然AnsiString在外表上跟以前的字符串类型几乎相同,但它是动态分配的并有自动回收功能,正是因为这个功能AnsiString有时被称为生存期自管理类型。Object Pascal能根据需要为字符串分配空间,所以不用像在C/C++中所担心的为中间结果分配缓冲区。另外,AnsiString字符串总是以null字符结束的,这使得AnsiString字符串能与Win32 API 中的字符串兼容。实际上,AnsiString类型是一个指向在堆栈中的字符串结构的指针。


    WideString类型像AnsiString一样是生存期自管理类型,它们都能动态分配、自动回收并且彼此能相互兼容,不过WideString和AnsiString的不同主要在三个方面:

    WideString由WideChar字符组成,而不是由AnsiChar字符组成的,它们跟Unicode字符串兼容。
    WideString用SysAllocStrLen()API函数进行分配,它们跟OLE的BSTR字符串相兼容。
    WideString没有引用计数,所以将一个WideString字符串赋值给另一个WideString字符串时,就需要从内存中的一个位置复制到另一个位置。这使得WideString在速度和内存的利用上不如AnsiString有效。

    Utf8String的定义同string, 但一般存放Utf8编码的字符串。

    UTF-8编码
    这是一种变长的编码方式:它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度,当字符在ASCII码的范围时,就用一个字节表示,保留了ASCII字符一个字节的编码做为它的一部分,如此一来UTF-8编码也可以是为视为一种对ASCII码的拓展。值得注意的是unicode编码中一个中文字符占2个字节,而UTF-8一个中文字符占3个字节。从unicode到uft-8并不是直接的对应,而是要过一些算法和规则来转换。
    在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
    用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件。

    附【Unicode 码表】

    0000-007F:C0控制符及基本拉丁文 (C0 Control and Basic Latin)
    0080-00FF:C1控制符及拉丁文补充-1 (C1 Control and Latin 1 Supplement)
    0100-017F:拉丁文扩展-A (Latin Extended-A)
    0180-024F:拉丁文扩展-B (Latin Extended-B)
    0250-02AF:国际音标扩展 (IPA Extensions)
    02B0-02FF:空白修饰字母 (Spacing Modifiers)
    0300-036F:结合用读音符号 (Combining Diacritics Marks)
    0370-03FF:希腊文及科普特文 (Greek and Coptic)
    0400-04FF:西里尔字母 (Cyrillic)
    0500-052F:西里尔字母补充 (Cyrillic Supplement)
    0530-058F:亚美尼亚语 (Armenian)
    0590-05FF:希伯来文 (Hebrew)
    0600-06FF:阿拉伯文 (Arabic)
    0700-074F:叙利亚文 (Syriac)
    0750-077F:阿拉伯文补充 (Arabic Supplement)
    0780-07BF:马尔代夫语 (Thaana)
    07C0-077F:西非書面語言 (N'Ko)
    0800-085F:阿维斯塔语及巴列维语 (Avestan and Pahlavi)
    0860-087F:Mandaic
    0880-08AF:撒马利亚语 (Samaritan)
    0900-097F:天城文书 (Devanagari)
    0980-09FF:孟加拉语 (Bengali)
    0A00-0A7F:锡克教文 (Gurmukhi)
    0A80-0AFF:古吉拉特文 (Gujarati)
    0B00-0B7F:奥里亚文 (Oriya)
    0B80-0BFF:泰米尔文 (Tamil)
    0C00-0C7F:泰卢固文 (Telugu)
    0C80-0CFF:卡纳达文 (Kannada)
    0D00-0D7F:德拉维族语 (Malayalam)
    0D80-0DFF:僧伽罗语 (Sinhala)
    0E00-0E7F:泰文 (Thai)
    0E80-0EFF:老挝文 (Lao)
    0F00-0FFF:藏文 (Tibetan)
    1000-109F:缅甸语 (Myanmar)
    10A0-10FF:格鲁吉亚语 (Georgian)
    1100-11FF:朝鲜文 (Hangul Jamo)
    1200-137F:埃塞俄比亚语 (Ethiopic)
    1380-139F:埃塞俄比亚语补充 (Ethiopic Supplement)
    13A0-13FF:切罗基语 (Cherokee)
    1400-167F:统一加拿大土著语音节 (Unified Canadian Aboriginal Syllabics)
    1680-169F:欧甘字母 (Ogham)
    16A0-16FF:如尼文 (Runic)
    1700-171F:塔加拉语 (Tagalog)
    1720-173F:Hanunóo
    1740-175F:Buhid
    1760-177F:Tagbanwa
    1780-17FF:高棉语 (Khmer)
    1800-18AF:蒙古文 (Mongolian)
    18B0-18FF:Cham
    1900-194F:Limbu
    1950-197F:德宏泰语 (Tai Le)
    1980-19DF:新傣仂语 (New Tai Lue)
    19E0-19FF:高棉语记号 (Kmer Symbols)
    1A00-1A1F:Buginese
    1A20-1A5F:Batak
    1A80-1AEF:Lanna
    1B00-1B7F:巴厘语 (Balinese)
    1B80-1BB0:巽他语 (Sundanese)
    1BC0-1BFF:Pahawh Hmong
    1C00-1C4F:雷布查语(Lepcha)
    1C50-1C7F:Ol Chiki
    1C80-1CDF:曼尼普尔语 (Meithei/Manipuri)
    1D00-1D7F:语音学扩展 (Phonetic Extensions)
    1D80-1DBF:语音学扩展补充 (Phonetic Extensions Supplement)
    1DC0-1DFF:结合用读音符号补充 (Combining Diacritics Marks Supplement)
    1E00-1EFF:拉丁文扩充附加 (Latin Extended Additional)
    1F00-1FFF:希腊语扩充 (Greek Extended)
    2000-206F:常用标点 (General Punctuation)
    2070-209F:上标及下标 (Superscripts and Subscripts)
    20A0-20CF:货币符号 (Currency Symbols)
    20D0-20FF:组合用记号 (Combining Diacritics Marks for Symbols)
    2100-214F:字母式符号 (Letterlike Symbols)
    2150-218F:数字形式 (Number Form)
    2190-21FF:箭头 (Arrows)
    2200-22FF:数学运算符 (Mathematical Operator)
    2300-23FF:杂项工业符号 (Miscellaneous Technical)
    2400-243F:控制图片 (Control Pictures)
    2440-245F:光学识别符 (Optical Character Recognition)
    2460-24FF:封闭式字母数字 (Enclosed Alphanumerics)
    2500-257F:制表符 (Box Drawing)
    2580-259F:方块元素 (Block Element)
    25A0-25FF:几何图形 (Geometric Shapes)
    2600-26FF:杂项符号 (Miscellaneous Symbols)
    2700-27BF:印刷符号 (Dingbats)
    27C0-27EF:杂项数学符号-A (Miscellaneous Mathematical Symbols-A)
    27F0-27FF:追加箭头-A (Supplemental Arrows-A)
    2800-28FF:盲文点字模型 (Braille Patterns)
    2900-297F:追加箭头-B (Supplemental Arrows-B)
    2980-29FF:杂项数学符号-B (Miscellaneous Mathematical Symbols-B)
    2A00-2AFF:追加数学运算符 (Supplemental Mathematical Operator)
    2B00-2BFF:杂项符号和箭头 (Miscellaneous Symbols and Arrows)
    2C00-2C5F:格拉哥里字母 (Glagolitic)
    2C60-2C7F:拉丁文扩展-C (Latin Extended-C)
    2C80-2CFF:古埃及语 (Coptic)
    2D00-2D2F:格鲁吉亚语补充 (Georgian Supplement)
    2D30-2D7F:提非纳文 (Tifinagh)
    2D80-2DDF:埃塞俄比亚语扩展 (Ethiopic Extended)
    2E00-2E7F:追加标点 (Supplemental Punctuation)
    2E80-2EFF:CJK 部首补充 (CJK Radicals Supplement)
    2F00-2FDF:康熙字典部首 (Kangxi Radicals)
    2FF0-2FFF:表意文字描述符 (Ideographic Description Characters)
    3000-303F:CJK 符号和标点 (CJK Symbols and Punctuation)
    3040-309F:日文平假名 (Hiragana)
    30A0-30FF:日文片假名 (Katakana)
    3100-312F:注音字母 (Bopomofo)
    3130-318F:朝鲜文兼容字母 (Hangul Compatibility Jamo)
    3190-319F:象形字注释标志 (Kanbun)
    31A0-31BF:注音字母扩展 (Bopomofo Extended)
    31C0-31EF:CJK 笔画 (CJK Strokes)
    31F0-31FF:日文片假名语音扩展 (Katakana Phonetic Extensions)
    3200-32FF:封闭式 CJK 文字和月份 (Enclosed CJK Letters and Months)
    3300-33FF:CJK 兼容 (CJK Compatibility)
    3400-4DBF:CJK 统一表意符号扩展 A (CJK Unified Ideographs Extension A)
    4DC0-4DFF:易经六十四卦符号 (Yijing Hexagrams Symbols)
    4E00-9FBF:CJK 统一表意符号 (CJK Unified Ideographs)
    A000-A48F:彝文音节 (Yi Syllables)
    A490-A4CF:彝文字根 (Yi Radicals)
    A500-A61F:Vai
    A660-A6FF:统一加拿大土著语音节补充 (Unified Canadian Aboriginal Syllabics Supplement)
    A700-A71F:声调修饰字母 (Modifier Tone Letters)
    A720-A7FF:拉丁文扩展-D (Latin Extended-D)
    A800-A82F:Syloti Nagri
    A840-A87F:八思巴字 (Phags-pa)
    A880-A8DF:Saurashtra
    A900-A97F:爪哇语 (Javanese)
    A980-A9DF:Chakma
    AA00-AA3F:Varang Kshiti
    AA40-AA6F:Sorang Sompeng
    AA80-AADF:Newari
    AB00-AB5F:越南傣语 (Vi?t Thái)
    AB80-ABA0:Kayah Li
    AC00-D7AF:朝鲜文音节 (Hangul Syllables)
    D800-DBFF:High-half zone of UTF-16
    DC00-DFFF:Low-half zone of UTF-16
    E000-F8FF:自行使用區域 (Private Use Zone)
    F900-FAFF:CJK 兼容象形文字 (CJK Compatibility Ideographs)
    FB00-FB4F:字母表達形式 (Alphabetic Presentation Form)
    FB50-FDFF:阿拉伯表達形式A (Arabic Presentation Form-A)
    FE00-FE0F:变量选择符 (Variation Selector)
    FE10-FE1F:竖排形式 (Vertical Forms)
    FE20-FE2F:组合用半符号 (Combining Half Marks)
    FE30-FE4F:CJK 兼容形式 (CJK Compatibility Forms)
    FE50-FE6F:小型变体形式 (Small Form Variants)
    FE70-FEFF:阿拉伯表達形式B (Arabic Presentation Form-B)
    FF00-FFEF:半型及全型形式 (Halfwidth and Fullwidth Form)
    FFF0-FFFF:特殊 (Specials)


    1.字符编码的发展
    第一阶段:ASCII阶段,(American Standard Code for Information Interchange, “美国信息交换标准码),计算机当时只支持英语,字符在计算机中都是以0和1的方式存储的。象a、b、c、d这样的52个字母(包括大写)、以及0、1、2等数字还有一些常用的符号(例如*、#、@等)在计算机中存储时也要使用二进制数来表示,而具体用哪些二进制数字表示哪个符号,就必须要有一定的规则,于是美国有关的标准化组织就出台了所谓的ASCII编码,统一规定了上述常用符号用哪个二进制数来表示。(来自百度百科),ASCII码规定每个字符例如“a”使用1个字节来表示,也就是8为的二进制组合,那么就有00000000-11111111一共256种组合,也就是可以表示256个不同的字符。

    其中0-31:是控制字符或通讯专用字符(不可以显示的字符,其余为可显示字符),如控制符:LF(换行)、CR(回车)等。

    32-126:是字符,其中32是空格。

    48-57为0-9的阿拉伯数字。

    65-90为26个大写英文字母。

    97-122为26个小写英文字母。

    其余的是一些标点符号,运算符号等。

    ASSCII共计有128个,从0到127,也就是从00000000-01111111,最高位都是0。

    第二阶段:ANSI编码(本地化)阶段,ASCII只能表示英文字符,那么其他字符怎么表示呢?汉语是这样解决的,用两个ASCII表示一个汉字,而且不用前面的128个。比如汉字“中”在中文操作系统中使用[0xD6,0xD0] 这两个字节存储,这样每个汉字也都有了自己的编码,汉字编码解决了,这就是中国的GB2312编码标准,但是这是中国汉字的编码,那么其他国家呢?其他的国家的计算机操作系统中可能把[0xD6,0xD0] 这两个字节存储成他们的文字,而不是“中”,不同的国家和地区制定了不同的标准,这些使用 2 个字节来代表一个字符的各种文字延伸编码方式,称为 ANSI 编码。

    (1)GB2312-80汉字编码

    GB2312国标字符集构成一个二维平面,它分成94行、94列,行号称为区号,列号称为位号。每一个汉字或符号在码表中都有各自的位置,字符的位置用它所在的区号(行号)及位号(列号)来表示。每个汉字的区号和位号分别用1个字节来表示,

    如:“大”字的区号20,位号83,区位码是20,83

    用2个字节表示为:00010100 01010011

    问题:信息通信中,汉字的区位码与通信使用的控制码(00H~1FH)发生冲突。

    解决方案:为避免汉字区位码与通信控制码冲突,ISO2022规定,每个汉字区号和位号必须分别加上32(即20H),

    即区位码加上2020H。

    经过这样处理得到的代码称为汉字的“国标交换码”(简称交换码)。因此,“大”字的国际交换码是:

    区位码(00010100 01010011)+ 2020H=国际交换码(00110100 01110011)

    机内码:

    问题:文本中汉字与西文字符经常混用,汉字信息如不予以特别的标识,它与单字节的标准ASCII码就会混淆不清。

    解决方法:把一个汉字看作两个扩展ASCII码,使表示GB2312汉字的两个字节的最高位(b7)加“1”,(即27=128=80H)。这种高位为l的双字节(16位)汉字编码就称为GB2312汉字的“机内码”,又称内码。
    “大”的国际交换码:(00110100 01110011),内码是:10110100 11110011(B4F3)

    第三阶段:UNICODE(国际化),为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。

    Unicode目前普遍采用的是UCS-2它用两个字节来编码一个字符一般用十六进制来表示UCS-2最多能编码65536个字符

    环境:win7中文旗舰版 + VS2010 + 当前代码页为GBK(GBK兼容GB2312,所以上面的例子,可以再当前环境下验证)

    string str1 = "123大";//GBK编码[31H,32H,33H,b4H,f3H]
    wstring str2 = L"123大";//UCS-2编码[0031H,0032H,0033H,5927H]
    string str3;
    int nlength = WideCharToMultiByte(CP_UTF8, 0, str2.c_str(), -1, NULL, 0, NULL, NULL);
    str3.resize(nlength, '');
    WideCharToMultiByte(CP_UTF8, 0, str2.c_str(), -1, &str3[0], nlength, NULL, NULL);//Unicode to UTF-8
    //str2 UTF-8编码[31H,32H,33H,E5H,a4H,a7H]

    1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

    2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

    例如:

    “大”字,UCS-2编码为[5927H],即[0101 1001 0010 0111]

    对于UTF-8编码来说,[5927H]在0800H~FFFFH之间,应该使用[1110 xxxx 10yy yyyy 10zz zzzz],将[0101 1001 0010 0111]以此填入xxxx yy yyyy zz zzzz部分,得

    [1110 0101 1010 0100 1010 0111],即 [e5H a4H a7H]

    好的代码像粥一样,都是用时间熬出来的
  • 相关阅读:
    架构师考试回顾
    精通 WPF UI Virtualization
    疑难杂症之Web客户端无法登录
    CDTray, 打开,关闭光驱的系统托盘程序
    原来Queryable是这样实现的..
    jQuery.Excel, 使用Ctrl+方向键/Home/End在input表格中移动
    nGoodPersonCards++
    C#数据库数据导入导出系列之三 数据库导出到Excel下
    调用webservice时提示对操作的回复消息正文进行反序列化时出错&&Web service 超过了最大请求长度
    ASP.NET网络映射驱动器无权限访问的解决方案(转)
  • 原文地址:https://www.cnblogs.com/jijm123/p/15255709.html
Copyright © 2020-2023  润新知