精华内容
下载资源
问答
  • Unicode字符集和多字节字符集关系 在最初的时候,Internet上只有一种字符集——ANSI的ASCII字符集,它使用7 bits来表示一个字符,总共表示128个字符,其中包括了英文字母、数字、标点符号等常用字符。之后,又进行...

    Unicode字符集和多字节字符集关系

      在最初的时候,Internet上只有一种字符集——ANSI的ASCII字符集,它使用7 bits来表示一个字符,总共表示128个字符,其中包括了英文字母、数字、标点符号等常用字符。之后,又进行扩展,使用8 bits表示一个字符,可以表示256个字符,主要在原来的7 bits字符集的基础上加入了一些特殊符号例如制表符。
      
      例如在GB-2312字符集中,“连通”的编码为C1 AC CD A8,其中C1和CD就是Leading Byte。前127个编码为标准ASCII保留,例如“0”的编码是30H(30H表示十六进制的30)。软件在读取时,如果看到30H,知道它小于128就是标准ASCII,表示“0”,看到C1大于128就知道它后面有一个另外的编码,因此C1 AC一同构成一个整个的编码,在GB-2312字符集中表示“连”。
      
      由于每种语言都制定了自己的字符集,导致最后存在的各种字符集实在太多,在国际交流中要经常转换字符集非常不便。因此,提出了Unicode字符集,它固定使用16 bits(两个字节、一个字)来表示一个字符,共可以表示65536个字符。将世界上几乎所有语言的常用字符收录其中,方便了信息交流。标准的Unicode称为UTF-16。后来为了双字节的Unicode能够在现存的处理单字节的系统上正确传输,出现了UTF-8,使用类似MBCS的方式对Unicode进行编码。注意UTF-8是编码,它属于Unicode字符集。Unicode字符集有多种编码形式,而ASCII只有一种,大多数MBCS(包括GB-2312)也只有一种。Unicode的最初目标,是用1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的文字,也不能解决传输的问题 (implantation head-ache’s),尤其在那些基于网络的应用中。已有的软件必须做大量的工作来程序16位的数据。因此,Unicode用一些基本的保留字符制定了三套编码方式。它们分别是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是以8位序列来编码的,用一个或几个字节来表示一个字符。这种方式的最大好处,是UTF-8保留了ASCII字符的编码做为它的一部分,例如,在UTF-8和ASCII中,“A”的编码都是0x41.UTF-16和UTF-32分别是Unicode的16位和32位编码方式。考虑到最初的目的,通常说的Unicode就是指UTF-16。

      例如“连通”两个字的Unicode标准编码UTF-16 (big endian)为:DE 8F 1A 90
      而其UTF-8编码为:E8 BF 9E E9 80 9A
      
      最后,当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件有三种途径来决定文本的字符集和编码: (其实我没看懂,但是还是记录下来了)
      最标准的途径是检测文本最开头的几个字节,如下表:

    开头字节 Charset/encoding

    EF BB BF UTF-8 
    FE FF UTF-16/UCS-2, little endian 
    FF FE UTF-16/UCS-2, big endian 
    FF FE 00 00 UTF-32/UCS-4, little endian.
    00 00 FE FF UTF-32/UCS-4, big-endian.例如插入标记后,连通”两个字的UTF-16 (big endian)和UTF-8码分别为: 
    FF FE DE 8F 1A 90 
    EF BB BF E8 BF 9E E9 80 9A 
    

      但是MBCS文本没有这些位于开头的字符集标记,更不幸的是,一些早期的和一些设计不良的软件在保存Unicode文本时不插入这些位于开头的字符集标记。因此,软件不能依赖于这种途径。这时,软件可以采取一种比较安全的方式来决定字符集及其编码,那就是弹出一个对话框来请示用户,例如将那个“连通”文件拖到MS Word中,Word就会弹出一个对话框。
      如果软件不想麻烦用户,或者它不方便向用户请示,那它只能采取自己“猜”的方法,软件可以根据整个文本的特征来猜测它可能属于哪个charset,这就很可能不准了。使用记事本打开那个“连通”文件就属于这种情况。
      我们可以证明这一点:在记事本中键入“连通”后,选择“Save As”,会看到最后一个下拉框中显示有“ANSI”,这时保存。当再当打开“连通”文件出现乱码后,再点击“File”->“Save As”,会看到最后一个下拉框中显示有“UTF-8”,这说明记事本认为当前打开的这个文本是一个UTF-8编码的文本。而我们刚才保存时是用ANSI字符集保存的。这说明,记事本猜测了“连通”文件的字符集,认为它更像一个UTF-8编码文本。这是因为“连通”两个字的GB-2312编码看起来更像UTF-8编码导致的,这是一个巧合,不是所有文字都这样。可以使用记事本的打开功能,在打开“连通”文件时在最后一个下拉框中选择ANSI,就能正常显示了。反过来,如果之前保存时保存为UTF-8编码,则直接打开也不会出现问题。
    如果将“连通”文件放入MS Word中,Word也会认为它是一个UTF-8编码的文件,但它不能确定,因此会弹出一个对话框询问用户,这时选择“简体中文(GB2312)”,就能正常打开了。记事本在这一点上做得比较简化罢了,这与这个程序的定位是一致的。

      需要提醒大家的是,部分Windows 2000字型无法显示所有的Unicode字符。如果发现文件中缺少了某些字符,只需将其变更为其它字型即可。

    big endian和little endian 
    

      big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。

    “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。 
    

      我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。

      Unicode big endian:在Big-endian处理器(如苹果Macintosh电脑)上建立的Unicode文件中的文字位元组(存放单位)排列顺序,与在Intel处理器上建立的文件的文字位元组排列顺序相反。最重要的位元组拥有最低的地址,且会先储存文字中较大的一端。为使这类电脑的用户能够存取你的文件,可选择Unicode big-endian格式。
      
    **********************************************************************

    ANSI字符,UNICODE,宽字符,窄字符,多字节字符集

    Unicode :宽字节字符集
    1. 如何取得一个既包含单字节字符又包含双字节字符的字符串的字符个数?

    可以调用Microsoft Visual C++的运行期库包含函数_mbslen来操作多字节(既包括单字节也包括双字节)字符串。 
    调用strlen函数,无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的0之前有多少个字节。 
    

    2. 如何对DBCS(双字节字符集)字符串进行操作?

    函数 描述 
    PTSTR CharNext ( LPCTSTR ); 返回字符串中下一个字符的地址 
    PTSTR CharPrev ( LPCTSTR, LPCTSTR ); 返回字符串中上一个字符的地址 
    BOOL IsDBCSLeadByte( BYTE ); 如果该字节是DBCS字符的第一个字节,则返回非0值 
    

    3. 为什么要使用Unicode?

    (1) 可以很容易地在不同语言之间进行数据交换。 
    (2) 使你能够分配支持所有语言的单个二进制.exe文件或DLL文件。 
    (3) 提高应用程序的运行效率。 
      Windows 2000是使用Unicode从头进行开发的,如果调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。进行这些字符串的转换需要占用系统的时间和内存。通过从头开始用Unicode来开发应用程序,就能够使你的应用程序更加有效地运行。 
      Windows CE 本身就是使用Unicode的一种操作系统,完全不支持ANSI Windows函数
      Windows 98 只支持ANSI,只能为ANSI开发应用程序。 
      Microsoft公司将COM从16位Windows转换成Win32时,公司决定需要字符串的所有COM接口方法都只能接受Unicode字符串。 
    

    4. 如何编写Unicode源代码?

      Microsoft公司为Unicode设计了WindowsAPI,这样,可以尽量减少代码的影响。实际上,可以编写单个源代码文件,以便使用或者不使用Unicode来对它进行编译。只需要定义两个宏(UNICODE和_UNICODE),就可以修改然后重新编译该源文件。
      _UNICODE宏用于C运行期头文件,而UNICODE宏则用于Windows头文件。当编译源代码模块时,通常必须同时定义这两个宏。
    5. Windows定义的Unicode数据类型有哪些?

    数据类型    说明 
    WCHAR Unicode字符 
    PWSTR 指向Unicode字符串的指针 
    PCWSTR 指向一个恒定的Unicode字符串的指针 
    对应的ANSI数据类型为CHAR,LPSTR和LPCSTR。 
    **ANSI/Unicode通用数据类型为TCHAR,PTSTR, LPCTSTR。** 
    

    6. 如何对Unicode进行操作?

    字符集 特性 实例 
    ANSI 操作函数以str开头 strcpy 
    Unicode 操作函数以wcs开头 wcscpy 
    MBCS 操作函数以_mbs开头 _mbscpy
    ANSI/Unicode 操作函数以_tcs开头 _tcscpy(C运行期库) 
    ANSI/Unicode 操作函数以lstr开头 lstrcpy(Windows函数)
    所有新的和未过时的函数在Windows2000中都同时拥有ANSI和Unicode两个版本。ANSI版本函数结尾以A表示;Unicode版本函数结尾以W表示。Windows会如下定义: 
    
    #ifdef UNICODE 
    #define CreateWindowEx CreateWindowExW 
    #else 
    #define CreateWindowEx CreateWindowExA 
    #endif // !UNICODE 
    

    7. 如何表示Unicode字符串常量?

     字符集 实例 
     ANSI “string” 
     Unicode L“string” 
     ANSI/Unicode T(“string”)或_TEXT(“string”)if( szError[0] == _TEXT(‘J’) ){ } 
    

    8. 为什么应当尽量使用操作系统函数?

      这将有助于稍稍提高应用程序的运行性能,因为操作系统字符串函数常常被大型应用程序比如操作系统的外壳进程Explorer.exe所使用。由于这些函数使用得很多,因此,在应用程序运行时,它们可能已经被装入RAM。 
      如:StrCat,StrChr,StrCmp和StrCpy等。 
    

    9.如何编写符合ANSI和Unicode的应用程序?

    (1) 将文本串视为字符数组,而不是chars数组或字节数组。 
    (2) 将通用数据类型(如TCHAR和PTSTR)用于文本字符和字符串。 
    (3) 将显式数据类型(如BYTE和PBYTE)用于字节、字节指针和数据缓存。 
    (4) 将TEXT宏用于原义字符和字符串。 
    (5) 执行全局性替换(例如用PTSTR替换PSTR)。 
    (6) 修改字符串运算问题。例如函数通常希望在字符中传递一个缓存的大小,而不是字节。这意味着不应该传递sizeof(szBuffer),而应该传递(sizeof(szBuffer)/sizeof(TCHAR)。另外,如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那么请记住要按字节来分配内存。这就是说,应该调用malloc(nCharacters *sizeof(TCHAR)),而不是调用malloc(nCharacters)。 
    

    10. 如何对字符串进行有选择的比较?

    通过调用CompareString来实现。 
    标志 含义 
    NORM_IGNORECASE 忽略字母的大小写 
    NORM_IGNOREKANATYPE 不区分平假名与片假名字符 
    NORM_IGNORENONSPACE 忽略无间隔字符 
    NORM_IGNORESYMBOLS 忽略符号 
    NORM_IGNOREWIDTH 不区分单字节字符与作为双字节字符的同一个字符 
    SORT_STRINGSORT 将标点符号作为普通符号来处理 
    

    11. 如何判断一个文本文件是ANSI还是Unicode?

    判断如果文本文件的开头两个字节是0xFF和0xFE,那么就是Unicode,否则是ANSI。 
    

    12. 如何判断一段字符串是ANSI还是Unicode?

    用IsTextUnicode进行判断。IsTextUnicode使用一系列统计方法和定性方法,以便猜测缓存的内容。由于这不是一种确切的科学方法,因此 IsTextUnicode有可能返回不正确的结果。 
    

    13. 如何在Unicode与ANSI之间转换字符串?

    **Windows函数MultiByteToWideChar用于将多字节字符串转换成宽字符串;函数WideCharToMultiByte将宽字符串转换成等价的多字节字符串。**
    

    展开全文
  • 首先DBCS是亚洲的字符集,包含了ANSI,ANSI也就是ASCII值为0-255之间的字符,当字符为ANSI时,存放于文件中占用的是一个字节。如果是非ANSI的呢,则占用两字节。用VB的ASC函数可以很容易得到一个字符的DBCS值(或是...
     
    

    Unicode字符集和多字节字符集关系

    在计算机中字符通常并不是保存为图像,每个字符都是使用一个编码来表示的,而每个字符究竟使用哪个编码代表,要取决于使用哪个字符集(charset)。 
    在最初的时候,Internet上只有一种字符集——ANSI的ASCII字符集,它使用7 bits来表示一个字符,总共表示128个字符,其中包括了英文字母、数字、标点符号等常用字符。之后,又进行扩展,使用8 bits表示一个字符,可以表示256个字符,主要在原来的7 bits字符集的基础上加入了一些特殊符号例如制表符。 
    后来,由于各国语言的加入,ASCII已经不能满足信息交流的需要,因此,为了能够表示其它国家的文字,各国在ASCII的基础上制定了自己的字符集,这些从ANSI标准派生的字符集被习惯的统称为ANSI字符集,它们正式的名称应该是MBCS(Multi-Byte Chactacter System,即多字节字符系统)。这些派生字符集的特点是以ASCII 127 bits为基础,兼容ASCII 127,他们使用大于128的编码作为一个Leading Byte,紧跟在Leading Byte后的第二(甚至第三)个字符与Leading Byte一起作为实际的编码。这样的字符集有很多,我们常见的GB-2312就是其中之一。 
    例如在GB-2312字符集中,“连通”的编码为C1 AC CD A8,其中C1和CD就是Leading Byte。前127个编码为标准ASCII保留,例如“0”的编码是30H(30H表示十六进制的30)。软件在读取时,如果看到30H,知道它小于128就是标准ASCII,表示“0”,看到C1大于128就知道它后面有一个另外的编码,因此C1 AC一同构成一个整个的编码,在GB-2312字符集中表示“连”。 
    由于每种语言都制定了自己的字符集,导致最后存在的各种字符集实在太多,在国际交流中要经常转换字符集非常不便。因此,提出了Unicode字符集,它固定使用16 bits(两个字节、一个字)来表示一个字符,共可以表示65536个字符。将世界上几乎所有语言的常用字符收录其中,方便了信息交流。标准的Unicode称为UTF-16。后来为了双字节的Unicode能够在现存的处理单字节的系统上正确传输,出现了UTF-8,使用类似MBCS的方式对Unicode进行编码。注意UTF-8是编码,它属于Unicode字符集。Unicode字符集有多种编码形式,而ASCII只有一种,大多数MBCS(包括GB-2312)也只有一种。Unicode的最初目标,是用1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的文字,也不能解决传输的问题 (implantation head-ache's),尤其在那些基于网络的应用中。已有的软件必须做大量的工作来程序16位的数据。因此,Unicode用一些基本的保留字符制定了三套编码方式。它们分别是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是以8位序列来编码的,用一个或几个字节来表示一个字符。这种方式的最大好处,是UTF-8保留了ASCII字符的编码做为它的一部分,例如,在UTF-8和ASCII中,“A”的编码都是0x41.UTF-16和UTF-32分别是Unicode的16位和32位编码方式。考虑到最初的目的,通常说的Unicode就是指UTF-16。 
    例如“连通”两个字的Unicode标准编码UTF-16 (big endian)为:DE 8F 1A 90 
    而其UTF-8编码为:E8 BF 9E E9 80 9A 
    最后,当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件有三种途径来决定文本的字符集和编码: 
    最标准的途径是检测文本最开头的几个字节,如下表: 

    开头字节 Charset/encoding 
    EF BB BF UTF-8 
    FE FF UTF-16/UCS-2, little endian 
    FF FE UTF-16/UCS-2, big endian 
    FF FE 00 00 UTF-32/UCS-4, little endian.

    00 00 FE FF UTF-32/UCS-4, big-endian.例如插入标记后,连通”两个字的UTF-16 (big endian)和UTF-8码分别为: 
    FF FE DE 8F 1A 90 
    EF BB BF E8 BF 9E E9 80 9A 
    但是MBCS文本没有这些位于开头的字符集标记,更不幸的是,一些早期的和一些设计不良的软件在保存Unicode文本时不插入这些位于开头的字符集标记。因此,软件不能依赖于这种途径。这时,软件可以采取一种比较安全的方式来决定字符集及其编码,那就是弹出一个对话框来请示用户,例如将那个“连通”文件拖到MS Word中,Word就会弹出一个对话框。 
    如果软件不想麻烦用户,或者它不方便向用户请示,那它只能采取自己“猜”的方法,软件可以根据整个文本的特征来猜测它可能属于哪个charset,这就很可能不准了。使用记事本打开那个“连通”文件就属于这种情况。 
    我们可以证明这一点:在记事本中键入“连通”后,选择“Save As”,会看到最后一个下拉框中显示有“ANSI”,这时保存。当再当打开“连通”文件出现乱码后,再点击“File”->“Save As”,会看到最后一个下拉框中显示有“UTF-8”,这说明记事本认为当前打开的这个文本是一个UTF-8编码的文本。而我们刚才保存时是用ANSI字符集保存的。这说明,记事本猜测了“连通”文件的字符集,认为它更像一个UTF-8编码文本。这是因为“连通”两个字的GB-2312编码看起来更像UTF-8编码导致的,这是一个巧合,不是所有文字都这样。可以使用记事本的打开功能,在打开“连通”文件时在最后一个下拉框中选择ANSI,就能正常显示了。反过来,如果之前保存时保存为UTF-8编码,则直接打开也不会出现问题。 
    如果将“连通”文件放入MS Word中,Word也会认为它是一个UTF-8编码的文件,但它不能确定,因此会弹出一个对话框询问用户,这时选择“简体中文(GB2312)”,就能正常打开了。记事本在这一点上做得比较简化罢了,这与这个程序的定位是一致的。 

    需要提醒大家的是,部分Windows 2000字型无法显示所有的Unicode字符。如果发现文件中缺少了某些字符,只需将其变更为其它字型即可。 

    big endian和little endian 

    big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。 

    “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。 

    我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。 

    Unicode big endian:在Big-endian处理器(如苹果Macintosh电脑)上建立的Unicode文件中的文字位元组(存放单位)排列顺序,与在Intel处理器上建立的文件的文字位元组排列顺序相反。最重要的位元组拥有最低的地址,且会先储存文字中较大的一端。为使这类电脑的用户能够存取你的文件,可选择Unicode big-endian格式。

    #####################################################################

    ANSI字符,UNICODE,宽字符,窄字符,多字节字符集

    Unicode :宽字节字符集 
    1. 如何取得一个既包含单字节字符又包含双字节字符的字符串的字符个数? 
    可以调用Microsoft Visual C++的运行期库包含函数_mbslen来操作多字节(既包括单字节也包括双字节)字符串。 
    调用strlen函数,无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的0之前有多少个字节。 
    2. 如何对DBCS(双字节字符集)字符串进行操作? 
    函数 描述 
    PTSTR CharNext ( LPCTSTR ); 返回字符串中下一个字符的地址 
    PTSTR CharPrev ( LPCTSTR, LPCTSTR ); 返回字符串中上一个字符的地址 
    BOOL IsDBCSLeadByte( BYTE ); 如果该字节是DBCS字符的第一个字节,则返回非0值 
    3. 为什么要使用Unicode? 
    (1) 可以很容易地在不同语言之间进行数据交换。 
    (2) 使你能够分配支持所有语言的单个二进制.exe文件或DLL文件。 
    (3) 提高应用程序的运行效率。 
    Windows 2000是使用Unicode从头进行开发的,如果调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。进行这些字符串的转换需要占用系统的时间和内存。通过从头开始用Unicode来开发应用程序,就能够使你的应用程序更加有效地运行。 
    Windows CE 本身就是使用Unicode的一种操作系统,完全不支持ANSI Windows函数
    Windows 98 只支持ANSI,只能为ANSI开发应用程序。 
    Microsoft公司将COM从16位Windows转换成Win32时,公司决定需要字符串的所有COM接口方法都只能接受Unicode字符串。 
    4. 如何编写Unicode源代码? 
    Microsoft公司为Unicode设计了WindowsAPI,这样,可以尽量减少代码的影响。实际上,可以编写单个源代码文件,以便使用或者不使用Unicode来对它进行编译。只需要定义两个宏(UNICODE和_UNICODE),就可以修改然后重新编译该源文件。 
    _UNICODE宏用于C运行期头文件,而UNICODE宏则用于Windows头文件。当编译源代码模块时,通常必须同时定义这两个宏。 
    5. Windows定义的Unicode数据类型有哪些? 
    数据类型 说明 
    WCHAR Unicode字符 
    PWSTR 指向Unicode字符串的指针 
    PCWSTR 指向一个恒定的Unicode字符串的指针 
    对应的ANSI数据类型为CHAR,LPSTR和LPCSTR。 
    ANSI/Unicode通用数据类型为TCHAR,PTSTR,LPCTSTR。 
    6. 如何对Unicode进行操作? 
    字符集 特性 实例 
    ANSI 操作函数以str开头 strcpy 
    Unicode 操作函数以wcs开头 wcscpy 
    MBCS 操作函数以_mbs开头 _mbscpy

    ANSI/Unicode 操作函数以_tcs开头 _tcscpy(C运行期库) 
    ANSI/Unicode 操作函数以lstr开头 lstrcpy(Windows函数)
    所有新的和未过时的函数在Windows2000中都同时拥有ANSI和Unicode两个版本。ANSI版本函数结尾以A表示;Unicode版本函数结尾以W表示。Windows会如下定义: 
    #ifdef UNICODE 
    #define CreateWindowEx CreateWindowExW 
    #else 
    #define CreateWindowEx CreateWindowExA 
    #endif // !UNICODE 
    7. 如何表示Unicode字符串常量? 
    字符集 实例 
    ANSI “string” 
    Unicode L“string” 
    ANSI/Unicode T(“string”)或_TEXT(“string”)if( szError[0] == _TEXT(‘J’) ){ } 
    8. 为什么应当尽量使用操作系统函数? 
    这将有助于稍稍提高应用程序的运行性能,因为操作系统字符串函数常常被大型应用程序比如操作系统的外壳进程Explorer.exe所使用。由于这些函数使用得很多,因此,在应用程序运行时,它们可能已经被装入RAM。 
    如:StrCat,StrChr,StrCmp和StrCpy等。 
    9.如何编写符合ANSI和Unicode的应用程序? 
    (1) 将文本串视为字符数组,而不是chars数组或字节数组。 
    (2) 将通用数据类型(如TCHAR和PTSTR)用于文本字符和字符串。 
    (3) 将显式数据类型(如BYTE和PBYTE)用于字节、字节指针和数据缓存。 
    (4) 将TEXT宏用于原义字符和字符串。 
    (5) 执行全局性替换(例如用PTSTR替换PSTR)。 
    (6) 修改字符串运算问题。例如函数通常希望在字符中传递一个缓存的大小,而不是字节。
    这意味着不应该传递sizeof(szBuffer),而应该传递(sizeof(szBuffer)/sizeof(TCHAR)。另外,如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那么请记住要按字节来分配内存。这就是说,应该调用malloc(nCharacters *sizeof(TCHAR)),而不是调用malloc(nCharacters)。 

    10. 如何对字符串进行有选择的比较? 
    通过调用CompareString来实现。 
    标志 含义 
    NORM_IGNORECASE 忽略字母的大小写 
    NORM_IGNOREKANATYPE 不区分平假名与片假名字符 
    NORM_IGNORENONSPACE 忽略无间隔字符 
    NORM_IGNORESYMBOLS 忽略符号 
    NORM_IGNOREWIDTH 不区分单字节字符与作为双字节字符的同一个字符 
    SORT_STRINGSORT 将标点符号作为普通符号来处理 
    11. 如何判断一个文本文件是ANSI还是Unicode? 
    判断如果文本文件的开头两个字节是0xFF和0xFE,那么就是Unicode,否则是ANSI。 
    12. 如何判断一段字符串是ANSI还是Unicode? 
    用IsTextUnicode进行判断。IsTextUnicode使用一系列统计方法和定性方法,以便猜测缓存的内容。由于这不是一种确切的科学方法,因此 IsTextUnicode有可能返回不正确的结果。 
    13. 如何在Unicode与ANSI之间转换字符串? 
    Windows函数MultiByteToWideChar用于将多字节字符串转换成宽字符串;函数WideCharToMultiByte将宽字符串转换成等价的多字节字符串。

    ________________________________________________________________

    UCS,UNICODE和UTF-8

    UCS,UNICODE和UTF-8

    本文简单介绍UCS,UNICODE和UTF-8,并利用C语言实现了UTF-8与UCS2之间的互相转化。
    1.什么是UCS和ISO10646?
    国际标准ISO10646定义了通用字符集(Universal Character Set, UCS). UCS是所有其它字符集标准的一个超集,它保证也其它字符集双向兼容,即编码间相互转换不会丢失任何信息。UCS字符集U+0000到U+007F与US-ASCII是一致的。 
    2.什么是UNICODE
    历史上, 有两个独立的, 创立单一字符集的尝试. 一个是国际标准化组织(ISO)的 ISO 10646 项目, 另一个是由(一开始大多是美国的)多语言软件制造商组成的协会组织的 Unicode 项目. 幸运的是, 1991年前后, 两个项目的参与者都认识到, 世界不需要两个不同的单一字符集. 它们合并双方的工作成果, 并为创立一个单一编码表而协同工作. 两个项目仍都存在并独立地公布各自的标准, 但 Unicode 协会和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 标准的码表兼容, 并紧密地共同调整任何未来的扩展.
    3.什么是UTF-8(一种传送和存储格式)
    UCS和UNICODE为每个字符分配了一个对应的整数,但并没有明确说明其实现机制.故存在多种编码方式,其中以两个字节和四个字节来存储一个字符的方法分别叫UCS-2, UCS-4,要将一个ASCII文件转换成一个UCS-2文件只要在每个字节前加一个字节0X00,转换成UCS-4只要在每个字节前加三个0X00。
    internet上大量的信息是以ASCII码存在的,如果都用两个字节来存储将浪费大量的资源,同时Unix和Linux下使用USC-2和USC-4会导致严重问题,于是出现了UTF-8(定义于ISO10646-1).
    UTF-8

    (UTF-8 stands for Unicode Transformation Format-8. It is an octet (8-bit) lossless encoding of Unicode characters.)
    UNICODE(UCS)和UTF-8的对应关系
    U-00000000 - U-0000007F0xxxxxxx (ASCII码 最重用)
    U-00000080 - U-000007FF: 110xxxxx 10xxxxxx (第二优先级常用)
    U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 
    U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
    U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
    U-04000000 - U-7FFFFFFF111111010xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (很少用)
    在多字节串中,第一个字节的开头‘1’的数目就是整个串中字节的数目.
    下面举UCS-2与UTF-8的对应关系,并利用C语言实现之间的互相转化。
    -----------------------------------------------------------------------------------------------------------
    | UCS2 | UTF-8 |
    |----------------------------------------------------------------------------------------------------------
    | | code | 1st Byte | 2nd byte | 3rd Byte |
    |--------------------------------------------------------------------------------------------------------
    | 000000000aaaaaaa | 0000 - 007F | 0aaaaaaa | | |
    |--------------------------------------------------------------------------------------------------------
    | 00000bbbbbaaaaaa | 0080 - 07FF | 110bbbbb | 10aaaaaa | |
    |--------------------------------------------------------------------------------------------------------
    ccccbbbbbbaaaaaa | 0800 - FFFF | 1110cccc | 10bbbbbb | 10aaaaaa |
    |--------------------------------------------------------------------------------------------------------

    alphajay的疑问: 这里是a b c应该是从0 1中取的一个bit位吧

    因为USC-2 每个字符用两个字节 16bit表示


    在这儿我只实现了单个字符的转换,串的转换也是一样的道理。
    1,把一个UTF-8字符转换成一个UCS-2字符。
    如果转换成功返回1,如果UTF-8字符是一个unrecognized字符,则返回0,且存一个blackbox(U+22e0)到ucs2_code_ptr中。

    typedef unsigned short UINT16;
    typedef unsigned char UINT8;
    typedef unsigned char BOOL;
    #define TRURE (BOOL)(1)
    #define FALSE (BOOL)(0)
    BOOL UTF8toUCS2Code(const UINT8* utf8_code, UINT16* ucs2_code){
    UINT16 temp1, temp2;
    BOOL is_unrecognized = FALSE ;
    UINT16 * in = utf8_code;
    if(!utf8_code || !ucs2_code){
    return is_unrecognized;
    }

    if(0x00 == (*in & 0x80)){
    /* 1 byte UTF-8 Charater.*/
    *ucs2_code= (UINT16)*in;
    is_unrecognized = TRUE;
    }
    else if(0xc0 == (*in & 0xe0) &&
    0x80 == (*(in + 1) & 0xc0)
    ){
    /* 2 bytes UTF-8 Charater.*/ 
    temp1 = (UINT16)(*in & 0x1f);
    temp1 <<= 6;
    temp1 |= (UINT16)(*(in + 1) & 0x3f);
    *ucs2_code = temp1;
    is_unrecognized = TRUE;
    }
    else if( 0xe0 == (*in & 0xf0) &&
    0x80 == (*(in +1) & 0xc0) &&
    0x80 == (*(in + 2) & 0xc0)
    ){
    /* 3bytes UTF-8 Charater.*/
    temp1 = (UINT16)(*in &0x0f);
    temp1 <<= 12;
    temp2 = (UINT16)(*(in+1) & 0x3F);
    temp2 <<= 6;
    temp1 = temp1 | temp2 | (UINT16)(*(in+2) & 0x3F);
    *ucs2_code = temp1;
    is_unrecognized = TRUE;
    }
    else{
    /* unrecognize byte. */ 
    *ucs2_code = 0x22e0;
    is_unrecognized = FALSE;
    }
    return is_unrecognized;
    }
    2,把一个UCS-2字符转换成UTF-8字符。函数返回转换成UTF-8的长度(字节1 -- 3),如果目标指针为空,返回0。
    UINT8 UCS2toUTF8Code(UINT16 ucs2_code, UINT8* utf8_code){
    int length = 0;
    UINT8* out = utf8_code;
    if(!utf8_code){
    return length;
    }
    if(0x0080 > ucs2_code){
    /* 1 byte UTF-8 Character.*/
    *out = (UINT8)ucs2_code;
    length++; 
    }
    else if(0x0800 > ucs2_code){
    /*2 bytes UTF-8 Character.*/
    *out = ((UINT8)(ucs2_code >> 6)) | 0xc0;
    *(out+1) = ((UINT8)(ucs2_code & 0x003F)) | 0x80;
    length += 2;
    }
    else{
    /* 3 bytes UTF-8 Character .*/
    *out = ((UINT8)(ucs2_code >> 12)) | 0xE0;
    *(out+1) = ((UINT8)((ucs2_code & 0x0FC0)>> 6)) | 0x80;
    *(out+2) = ((UINT8)(ucs2_code & 0x003F)) | 0x80;
    length += 3; 
    }
    return length;
    }
    字符串间的转换也是一样的。

    [概述]
    计算机中的一切都是以数字来表示的,字符同样如此。字符编码就是将字符集编码成为数字序列,以便能让计算机识别。各个地区和国家使用的语言有别,将本地使用的语言符号进行编码就得到本地编码字符集。例如西欧国家使用的本地编码是ISO8859-1,中国大陆和新加坡等地区使用本地编码是GB2312或GBK,中国港台地区使用的本地编码是BIG5,韩国和日本的本地编码分别是euc-kr和Shift_JIS。电脑的操作系统支持各种本地编码字符集,操作系统默认的本地编码和你所安装的操作系统语言版本是一致的。本地集只对本地使用的文字符号进行了编码,并不包括其他地区使用的文字,即使两个本地集中包含了相同的字符,这个字符的编码值也是不同的。例如“中”的GB2312或GBK编码值为“0xD6D0”,而BIG5编码值为“0xA4A4”。
    全球信息交流与融合的趋势要求实现对本地字符集的统一,1984年4月ISO成立了工作组,针对各国文字、符号进行统一编码,这种编码成为Unicode。Unicode于1992年6月通过DIS(DrafInternationalStandard),V2.0版本于1996年发布。Unicode编码包括了符号6811个、汉字20902个、韩文11172个、等等。Unicode虽然实现了全球统一编码,但是在字符集数量和编码效率方面显然存在着不足,而UTF-8、UTF-16就是针对Unicode编码进行转换或扩充形成的编码,UTF是Unicode Translation Format的缩写。

    [细节]
    关于ASCII编码
    ASCII编码是美国标准信息交换码,这种编码方式针对的是英文字符。ASCII编码使用一个字节对字符进行编码,而且字节的最高位都为0,因此ASCII编码的字符集大小是128个。由于英文字母仅有26个,再加上其他一些常用符号,总大小也不会超过128个,因此ASCII编码的空间是足够的。例如,字符“a”被编码为0x61,字符“b”被编码为0x62等等。注意,在有的时候ASCII泛指本地编码,例如文本编辑器UltraEdit中有诸如“ASCII转Unicode”的功能,这里的ASCII就泛指本地编码,如果本地编码是GBK,这个功能执行的就是GBK编码到Unicode编码的转换。

    关于ISO8859-1编码
    ISO8859-1是西欧语系国家通用的字符集编码,ISO8859-1使用一个字节对字符进行编码,编码值范围是0x00-0xFF。其中,0x00-0x1F用作控制字,0x20-0x7F表示字母、数字和符号这些图形字符,0xA0-0xFF作为附加部分使用。由于ASCII编码只使用了一个字节中的低7位,编码范围仅为0-127,虽然可以容纳英文字符和其他的一些符号,但是却不能包含除英文以外的其他西欧语言的字母,因此ASCII编码在西欧国家并不通用。针对这个问题ISO在ASCII编码的基础上进行了扩充,制定了ISO8859-1编码,ISO8859-1编码使用了一个字节的全部8位,编码范围是0-255,能包含西欧语系的所有字母和符号。

    关于GB2312、GBK和BIG5编码
    GB2312码是中华人民共和国国家汉字信息交换使用码,全称《信息交换使用汉字编码字符集-基本集》,由国家标准总局发布,1981年5月1日实施,中国大陆和新加坡等地使用此编码。GB2312收录了简化汉字、符号、字母、日文假名等共计7445个字符,其中汉字占6763个。GB2312将代码表分区94个区(0xA1-0xFE),对应第一个字节,每个区94个位(0xA1-0xFE),对应了第二字节,两个字节的值分别为区号的值和位号的值加32(0x20),因此也被称为区位码。GB2312的编码范7围是0x2121-0x777E,与ASCII有重叠,通常方法是将GB码的两个字节的最高位置1区别
    GBK是GB2312-80的扩展,向上兼容,包含了20902个汉字,编码范围是0x8140-0xFEFE,剔除高位0x80的字位,其他字符都可以一一映射到Unicode2.0。GB18030-2000(GBK2K)在GBK的基础上增加了藏、蒙等少数民族的字符,GBK2K从根本上解决了字位不够、字形不足的问题。GBK2K首先要求实现能够完全映射到Unicode3.0标准的所有字形,现在还没有任何一个操作系统支持GBK2K。
    BIG5码被称为大五码,是中国港台地区使用的字符编码方式。TW-BIG5码将所有字分为两大群,即常用字区和次常用字区,每个字区分都采用笔画排序,同笔画的字依部首排序。TW-BIG5每个字由两个字节组成

    展开全文
  • 多字节字符集错误

    千次阅读 2016-03-18 12:55:01
    字符集设置,使用Unicode自负自,改为使用多字节字符集 1>d:\lianxi20160303\sockettest\test1\test1\clientsocket.cpp(35): error C2664: “CListBox::SetTopIndex”: 不能将参数 1 从“Ctest1Dlg *”转换...
    1>d:\lianxi20160303\sockettest\test1\test1\test1dlg.cpp(172): error C2664: “void ATL::CStringT<BaseType,StringTraits>::Format(const wchar_t *,...)”: 不能将参数 1 从“const char [12]”转换为“const wchar_t *”
    1>          with
    1>          [
    1>              BaseType=wchar_t,
    1>              StringTraits=StrTraitMFC_DLL<wchar_t>
    1>          ]
    1>          与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换
    1>d:\lianxi20160303\sockettest\test1\test1\test1dlg.cpp(196): error C2664: “CListBox::AddString”: 不能将参数 1 从“const char [13]”转换为“LPCTSTR”
    1>          与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换

    以上错误的发生

    // TODO: 在此添加控件通知处理程序代码
    	//连接服务器
    	BYTE nField[4];
    	CString sIP;
    	UpdateData();
    	m_ServerIP.GetAddress(nField[0], nField[1],nField[2],nField[3]);
    	sIP.Format("%d.%d.%d.%d", nField[0], nField[1],nField[2],nField[3]);

    多字节字符集,所以LPTSTR是char*而不是wchar_t*
    求长度用的是strlen不是wcslen
     
    

    字符集设置,使用Unicode自负自,改为使用多字节字符集

    1>d:\lianxi20160303\sockettest\test1\test1\clientsocket.cpp(35): error C2664: “CListBox::SetTopIndex”: 不能将参数 1 从“Ctest1Dlg *”转换为“int”
    1>          没有使该转换得以执行的上下文
    1>d:\lianxi20160303\sockettest\test1\test1\clientsocket.cpp(35): error C2227: “->m_ListWords”的左边必须指向类/结构/联合/泛型类型
    1>d:\lianxi20160303\sockettest\test1\test1\clientsocket.cpp(35): error C2228: “.GetCount”的左边必须有类/结构/联合
    1>d:\lianxi20160303\sockettest\test1\test1\clientsocket.cpp(35): error C2059: 语法错误:“)”
    1>

    这些问题,只是因为程序中少了一个括号


    void CClientSocket::OnConnect(int nErrorCode)
    {
    	// TODO: 在此添加专用代码和/或调用基类
    //#include "test1Dlg.h"
    	if(nErrorCode)
    	{
    		AfxMessageBox("连接失败,请您重试");
    		return ;
    	}
    	((Ctest1Dlg*) (AfxGetApp()->m_pMainWnd))->m_ListWords.AddString("连接服务器成功");
    
    	((Ctest1Dlg*) (AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex( ((Ctest1Dlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);
    
    	CAsyncSocket::OnConnect(nErrorCode);
    }


    展开全文
  • UNICODE与多字节字符集的区别及转换

    千次阅读 2016-09-27 17:14:57
    在最初的时候,Internet上只有一种字符集——ANSI的ASCII字符集,它使用7 bits来表示一个字符,总共表示128个字符,其中包括了英文字母、数字、标点符号等常用字符。之后,又进行扩展,使用8 bits表示一个字符,可

    一、一点历史

    在计算机中字符通常并不是保存为图像,每个字符都是使用一个编码来表示的,而每个字符究竟使用哪个编码代表,要取决于使用哪个字符集(charset)。 在最初的时候,Internet上只有一种字符集——ANSI的ASCII字符集,它使用7 bits来表示一个字符,总共表示128个字符,其中包括了英文字母、数字、标点符号等常用字符。之后,又进行扩展,使用8 bits表示一个字符,可以表示256个字符,主要在原来的7 bits字符集的基础上加入了一些特殊符号例如制表符。 后来,由于各国语言的加入,ASCII已经不能满足信息交流的需要,因此,为了能够表示其它国家的文字,各国在ASCII的基础上制定了自己的字符集,这些从ANSI标准派生的字符集被习惯的统称为ANSI字符集,它们正式的名称应该是MBCS(Multi-Byte Chactacter System,即多字节字符系统)。


      这些派生字符集的特点是以ASCII 127 bits为基础,兼容ASCII 127,他们使用大于128的编码作为一个Leading Byte,紧跟在Leading Byte后的第二(甚至第三)个字符与Leading Byte一起作为实际的编码。这样的字符集有很多,我们常见的GB-2312就是其中之一。 例如在GB-2312字符集中,“连通”的编码为C1 AC CD A8,其中C1和CD就是Leading Byte。前127个编码为标准ASCII保留,例如“0”的编码是30H(30H表示十六进制的30)。软件在读取时,如果看到30H,知道它小于128就是标准ASCII,表示“0”,看到C1大于128就知道它后面有一个另外的编码,因此C1 AC一同构成一个整个的编码,在GB-2312字符集中表示“连”。 由于每种语言都制定了自己的字符集,导致最后存在的各种字符集实在太多,在国际交流中要经常转换字符集非常不便。因此,提出了Unicode字符集,它固定使用16 bits(两个字节、一个字)来表示一个字符,共可以表示65536个字符。将世界上几乎所有语言的常用字符收录其中,方便了信息交流。标准的Unicode称为UTF-16。后来为了双字节的Unicode能够在现存的处理单字节的系统上正确传输,出现了UTF-8,使用类似MBCS的方式对Unicode进行编码。注意UTF-8是编码,它属于Unicode字符集。Unicode字符集有多种编码形式,而ASCII只有一种,大多数MBCS(包括GB-2312)也只有一种。Unicode的最初目标,是用1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的文字,也不能解决传输的问题 (implantation head-ache's),尤其在那些基于网络的应用中。已有的软件必须做大量的工作来程序16位的数据。因此,Unicode用一些基本的保留字符制定了三套编码方式。它们分别是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是以8位序列来编码的,用一个或几个字节来表示一个字符。这种方式的最大好处,是UTF-8保留了ASCII字符的编码做为它的一部分,例如,在UTF-8和ASCII中,“A”的编码都是0x41.UTF-16和UTF-32分别是Unicode的16位和32位编码方式。


      考虑到最初的目的,通常说的Unicode就是指UTF-16。 例如“连通”两个字的Unicode标准编码UTF-16 (big endian)为:DE 8F 1A 90而其UTF-8编码为:E8 BF 9E E9 80 9A 最后,当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件有三种途径来决定文本的字符集和编码: 最标准的途径是检测文本最开头的几个字节,如下表:开头字节 Charset/encodingEF BB BF UTF-8FE FF UTF-16/UCS-2, little endianFF FE UTF-16/UCS-2, big endianFF FE 00 00 UTF-32/UCS-4, little endian.00 00 FE FF UTF-32/UCS-4, big-endian.例如**标记后,连通”两个字的UTF-16 (big endian)和UTF-8码分别为:FF FE DE 8F 1A 90EF BB BF E8 BF 9E E9 80 9A 但是MBCS文本没有这些位于开头的字符集标记,更不幸的是,一些早期的和一些设计不良的软件在保存Unicode文本时不**这些位于开头的字符集标记。因此,软件不能依赖于这种途径。这时,软件可以采取一种比较安全的方式来决定字符集及其编码,那就是弹出一个对话框来请示用户,例如将那个“连通”文件拖到MS Word中,Word就会弹出一个对话框。 如果软件不想麻烦用户,或者它不方便向用户请示,那它只能采取自己“猜”的方法,软件可以根据整个文本的特征来猜测它可能属于哪个charset,这就很可能不准了。使用记事本打开那个“连通”文件就属于这种情况。


      我们可以证明这一点:在记事本中键入“连通”后,选择“Save As”,会看到最后一个下拉框中显示有“ANSI”,这时保存。当再当打开“连通”文件出现乱码后,再点击“File”->“Save As”,会看到最后一个下拉框中显示有“UTF-8”,这说明记事本认为当前打开的这个文本是一个UTF-8编码的文本。而我们刚才保存时是用ANSI字符集保存的。这说明,记事本猜测了“连通”文件的字符集,认为它更像一个UTF-8编码文本。这是因为“连通”两个字的GB-2312编码看起来更像UTF-8编码导致的,这是一个巧合,不是所有文字都这样。可以使用记事本的打开功能,在打开“连通”文件时在最后一个下拉框中选择ANSI,就能正常显示了。反过来,如果之前保存时保存为UTF-8编码,则直接打开也不会出现问题。 如果将“连通”文件放入MS Word中,Word也会认为它是一个UTF-8编码的文件,但它不能确定,因此会弹出一个对话框询问用户,这时选择“简体中文(GB2312)”,就能正常打开了。


      记事本在这一点上做得比较简化罢了,这与这个程序的定位是一致的。需要提醒大家的是,部分Windows 2000字型无法显示所有的Unicode字符。如果发现文件中缺少了某些字符,只需将其变更为其它字型即可。big endian和little endianbig endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。Unicode big endian:在Big-endian处理器(如苹果Macintosh电脑)上建立的Unicode文件中的文字位元组(存放单位)排列顺序,与在Intel处理器上建立的文件的文字位元组排列顺序相反。最重要的位元组拥有最低的地址,且会先储存文字中较大的一端。为使这类电脑的用户能够存取你的文件,可选择Unicode big-endian格式。


      应该说Unicode字符集更加通用,但这里读取目录因为用到Windows.h里面的一些东西,所以需要多字节字符集,毕竟Microsoft的东西兼容性一直不太好,所以如果可以的话,还是使用Unicode字符集比较好!


    二、UNICODE与多字节字符集

    VS2008默认的字符集是Unicode,而VC6.0默认是多字节字符集,Unicode字符集你要加_T("")或L"",你也可以“

    工程-属性-修改字符集”。


     1. UNICODE:它是用两个字节表示一个字符的方法。比如字符'A'在ASCII下面是一个字符,可'A'在UNICODE下面是两个字符,高字符用0填充,而且汉字'程'在ASCII下面是两个字节,而在UNICODE下仍旧是两个字节。UNICODE的用处就是定长表示世界文字,据统计,用两个字节可以编码现存的所有文字而没有二义。 

     
     2. MBCS,它是多字节字符集,它是不定长表示世界文字的编码。MBCS表示英文字母时就和ASCII一样(这也是我们容易把MBCS和ASCII搞混的原因),但表示其他文字时就需要用多字节。

     

    WINDOWS下面的程序设计可以支持MBCS和UNICODE两种编码的字符串,具体用那种就看你定义了MBCS宏还是UNICODE宏。MBCS宏对应的字符串指针是char*也就是LPSTR,UNICODE对应的指针是unsigned   short*也就是LPWSTR,为了写程序方便微软定义了类型LPTSTR,在MBCS下他就是char*,   在UNICODE下它unsigned  

    char*,这样你就可以重定义一个宏进行不同字符集的转换了。


    3. LPTSTR、LPCSTR、LPCTSTR、LPSTR的意义

    LPSTR:  32-bit指针 指向一个字符串,每个字符占1字节
    LPCSTR:  32-bit指针 指向一个常字符串,每个字符占1字节
    LPCTSTR: 32-bit指针 指向一个常字符串,每字符可能占1字节或2字节,取决于Unicode是否定义
    LPTSTR:  32-bit指针 每字符可能占1字节或2字节,取决于Unicode是否定义

     

    Windows使用两种字符集ANSI和UNICODE,前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况。而后者是双字节方式,方便处理双字节字符。WindowsNT的所有与字符有关的函数都提供两种方式的版本,而Windows9x只支持ANSI方式。_T一般同字常数相关,如_T("Hello"。如果你编译一个程序为ANSI方式,_T实际不起任何作用。而如果编译一个程序为UNICODE方式,则编译器会把"Hello"字符串以UNICODE方式保存。_T和_L的区别在于,_L不管你是以什么方式编译,一律以UNICODE方式保存.

     

     4. 例1:

    Windows核心编程的第一章。

    L是表示字符串资源为Unicode的。

    比如wchar_t Str[] = L"Hello World!";    这个就是双子节存储字符了。

    _T是一个适配的宏~

    当#ifdef _UNICODE的时候_T就是L

    没有#ifdef _UNICODE的时候_T就是ANSI的。

     

    比如

    LPTSTR lpStr = new TCHAR[32];
    TCHAR* szBuf = _T("Hello");
    以上两句使得无论是在UNICODE编译条件下都是正确编译的。

    而且MS推荐你使用相匹配的字符串函数。
    比如处理LPTSTR或者LPCTSTR 的时候,不要用strlen ,而是要用_tcslen

    否则在UNICODE的编译条件下,strlen不能处理 wchar_t*的字符串。

    T是非常有意思的一个符号(TCHAR、LPCTSTR、LPTSTR、_T()、_TEXT()...),它表示使用一种中间类型,既不明确表示使用 MBCS,也不明确表示使用 UNICODE。那到底使用哪种字符集?编译的时候才决定


    在大多数情况下,CString 转换成 LPTSTR是非常容易的,如果函数要求传入LPTSTR型的参数,直接传一个

    CString也行,但是在visual studio 2008中,却偶尔会出现不能转换的情况,这个为什么呢?

    有人以为这是ASCII(多字节)与Unicode(宽字节)之间的问题,其实不是,要知LPTSTR这个宏是随编译器参数不同而不同的,如果在编译器——常规里面设置程序按ASCII编译,那LPTSTR就表示char*,如果选择Unicode

    编译那就是wchar_t*。CString也是如此,随编译器选项的不同,可以是ASCII字符串也可以是Unicode字符串。

    那么CString与LPTSTR,要么全是多字节,要么全是宽字节,不可能存在两者之间不能转换的问题。

     

    例2:

    1. 如何将 CString 型转换为 LPBYTE 
    CString   str;   
    LPBYTE   by   =   (LPBYTE)(LPCSTR)str;

     

    2. LPBYTE 如何转为CString 型

    CString   str;

    str.Format("%s", by);


     

    在vc++中有着各种字符串的表示法,如您所说。               
          首先char*     是指向ANSI字符数组的指针,其中每个字符占据8位(有效数据是除掉最高位的其他7位),这里保持了与传统的C,C++的兼容。           
      LP的含义是长指针(long     pointer)。
    LPSTR是一个指向以‘’结尾的ANSI字符数组的指针,与char*可以互换使用,在win32中较多地使用LPSTR。而LPCSTR中增加的‘C’的含义是“CONSTANT”(常量),表明这种数据类型的实例不能被使用它的API函数改变,除此之外,它与LPSTR是等同的。       
           为了满足程序代码国际化的需要,业界推出了Unicode标准,它提供了一种简单和一致的表达字符串的方法,所有字符中的字节都是16位的值,其数量也可以满足差不多世界上所有书面语言字符的编码需求,开发程序时使用Unicode(类型为wchar_t)是一种被鼓励的做法。       
           LPWSTR与LPCWSTR由此产生,它们的含义类似于LPSTR与LPCSTR,只是字符数据是16位的wchar_t而不是char。             
      然后为了实现两种编码的通用,提出了TCHAR的定义:     
    如果定义_UNICODE,声明如下:         typedef     wchar_t     TCHAR;       
    如果没有定义_UNICODE,则声明如下:         typedef     char     TCHAR;         
    LPTSTR和LPCTSTR中的含义就是每个字符是这样的TCHAR。             
    CString类中的字符就是被声明为TCHAR类型的,它提供了一个封装好的类供用户方便地使用。

    注意:

    这两个函数是由Windows提供的转换函数,不具有通用性

    C语言提供的转换函数为mbstowcs()/wcstombs()

    一、函数简单介绍

    涉及到的头文件:

    函数所在头文件:windows.h

    #include <windows.h>

    wchar_t类型所需头文件:wchar.h

    #include <wchar.h>

    ( 1 ) MultiByteToWideChar()

    函数功能:该函数映射一个字符串到一个宽字符(unicode)的字符串。由该函数映射的字符串没必要是多字节字符组。 

    函数原型: 

    int MultiByteToWideChar(

      UINT CodePage,
      DWORD dwFlags,
      LPCSTR lpMultiByteStr,
      int cchMultiByte,
      LPWSTR lpWideCharStr,
      int cchWideChar
      );

    参数:

    1> CodePage:指定执行转换的多字节字符所使用的字符集

    这个参数可以为系统已安装或有效的任何字符集所给定的值。你也可以指定其为下面的任意一值:

    Value Description
    CP_ACP ANSI code page
    CP_MACCP Not supported
    CP_OEMCP OEM code page
    CP_SYMBOL Not supported
    CP_THREAD_ACP Not supported
    CP_UTF7 UTF-7 code page
    CP_UTF8 UTF-8 code page
    2> dwFlags:一组位标记,用以指出是否未转换成预作或宽字符(若组合形式存在),是否使用象形文字替代控制字符,以及如何处理无效字符。你可以指定下面是标记常量的组合,含义如下:
      MB_PRECOMPOSED:通常使用预作字符——就是说,由一个基本字符和一个非空字符组成的字符只有一个单一的字符值。这是缺省的转换选择。不能与MB_COMPOSITE值一起使用。
      MB_COMPOSITE:通常使用组合字符——就是说,由一个基本字符和一个非空字符组成的字符分别有不同的字符值。不能与MB_PRECOMPOSED值一起使用。
      MB_ERR_INVALID_CHARS:如果函数遇到无效的输入字符,它将运行失败,且GetLastErro返回ERROR_NO_UNICODE_TRANSLATION值。
      MB_USEGLYPHCHARS:使用象形文字替代控制字符。 
    组合字符由一个基础字符和一个非空字符构成,每一个都有不同的字符值。每个预作字符都有单一的字符值给基础/非空字符的组成。在字符è中,e就是基础字符,而重音符标记就是非空字符。 
    标记MB_PRECOMPOSED和MB_COMPOSITE是互斥的,而标记MB_USEGLYPHCHARS和MB_ERR_INVALID_CHARS则不管其它标记如何都可以设置。 
    一般不使用这些标志,故取值为0时。
    3> lpMultiByteStr:指向 待转换的字符串的缓冲区。 
    4> cchMultiByte:指定由参数 lpMultiByteStr指向的字符串中字节的个数。可以设置为-1,会自动判断lpMultiByteStr指定的字符串的长度
    (如果字符串不是以空字符中止,设置为-1可能失败,可能成功),此参数设置为0函数将失败。 
    5> lpWideCharStr:指向 接收被转换字符串的缓冲区。 
    6> cchWideChar:指定由参数 lpWideCharStr指向的缓冲区的宽字节数。若此值为0,函数不会执行转换,而是返回目标缓存lpWideChatStr所需的宽字符数。
    返回值:

    如果函数运行成功,并且cchWideChar不为0,返回值是由lpWideCharStr指向的缓冲区中写入的宽字符数;

    如果函数运行成功,并且cchMultiByte为0,返回值是待转换字符串的缓冲区所需求的宽字符数大小。(此种情况用来获取转换所需的wchar_t的个数)

    如果函数运行失败,返回值为零。

    若想获得更多错误信息,请调用GetLastError()函数。它可以返回下面所列错误代码:

      ERROR_INSUFFICIENT_BUFFER;     ERROR_INVALID_FLAGS;
      ERROR_INVALID_PARAMETER;         ERROR_NO_UNICODE_TRANSLATION。
    ( 2 ) WideCharToMultiByte()

    函数功能:该函数映射一个unicode字符串到一个多字节字符串。 

    函数原型: 

    int WideCharToMultiByte(

      UINT  CodePage,
      DWORD  dwFlags,
      LPCWSTR  lpWideCharStr,
      int  cchWideChar,
      LPSTR  lpMultiByteStr,
      int  cchMultiByte,
      LPCSTR  lpDefaultChar,
      LPBOOL  pfUsedDefaultChar
      );

    参数:

    与MultiByteToWideChar()函数中的参数类似,但是多了两个参数:

    lpDefaultCharpfUsedDefaultChar:只有当WideCharToMultiByte函数遇到一个宽字节字符,而该字符在uCodePage参数标识的代码页中并没有它的表示法时,WideCharToMultiByte函数才使用这两个参数。(通常都取值为NULL)

    1> 如果宽字节字符不能被转换,该函数便使用lpDefaultChar参数指向的字符。如果该参数是NULL(这是大多数情况下的参数值),那么该函数使用系统的默认字符。该默认字符通常是个问号。这对于文件名来说是危险的,因为问号是个通配符。

    2> pfUsedDefaultChar参数指向一个布尔变量,如果Unicode字符串中至少有一个字符不能转换成等价多字节字符,那么函数就将该变量置为TRUE。如果所有字符均被成功地转换,那么该函数就将该变量置为FALSE。当函数返回以便检查宽字节字符串是否被成功地转换后,可以测试该变量。

    返回值

    如果函数运行成功,并且cchMultiByte不为零,返回值是由 lpMultiByteStr指向的缓冲区中写入的字节数;

    如果函数运行成功,并且cchMultiByte为零,返回值是接收到待转换字符串的缓冲区所必需的字节数。(此种情况用来获取转换所需Char的个数)

    如果函数运行失败,返回值为零。

    若想获得更多错误信息,请调用GetLastError函数。它可以返回下面所列错误代码:

      ERROR_INSUFFICIENT_BJFFER;ERROR_INVALID_FLAGS;
      ERROR_INVALID_PARAMETER;ERROR_NO_UNICODE_TRANSLATION。

    二、使用方法

    ( 1 ) 将多字节字符串转为宽字符串:

    1) 调用MultiByteToWideChar()函数,设置cchWideChar参数为0(用以获取转换所需的接收缓冲区大小);

    2) 获取输入缓存的大小,作为cchMultiByte的值;(这样做是为了节省空间,也可以给cchMultiByte取值-1(字符串需要以空字符结尾,否则会出错))

    3) 分配足够的内存块,用于存放转换后的Unicode字符串;

    该内存块的大小由前面对cchWideChar()函数的返回值来决定;(也可以用别的方法,但该方法更节省内存)

    4) 再次调用MultiByteToWideChar()函数,这次将缓存的地址作为lpWideCharStr,参数来传递,并传递第一次调用MultiByteToWideChar()函数时返回值作为cchWideChar参数的值;

    5) 使用转换后的字符串;

    6) 释放接收缓冲区占用的内存块;

    示例代码:

    [cpp]  view plain  copy
    1. void main()  
    2. {  
    3.     char sBuf[25]={0};  
    4.   
    5.     strcpy(sBuf, "我最棒");  
    6.   
    7.     //获取输入缓存大小  
    8.     int sBufSize=strlen(sBuf);  
    9.     //获取输出缓存大小  
    10.     //VC++ 默认使用ANSI,故取第一个参数为CP_ACP  
    11.     DWORD dBufSize=MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, NULL, 0);  
    12.     printf("需要wchar_t%u个\n", dBufSize);  
    13.   
    14.     wchar_t * dBuf=new wchar_t[dBufSize];  
    15.     wmemset(dBuf, 0, dBufSize);  
    16.   
    17.     //进行转换  
    18.     int nRet=MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, dBuf, dBufSize);  
    19.       
    20.     if(nRet<=0)  
    21.     {  
    22.         cout<<"转换失败"<<endl;  
    23.         DWORD dwErr=GetLastError();  
    24.         switch(dwErr)  
    25.         {  
    26.         case ERROR_INSUFFICIENT_BUFFER:  
    27.             printf("ERROR_INSUFFICIENT_BUFFER\n");  
    28.             break;  
    29.         case ERROR_INVALID_FLAGS:  
    30.             printf("ERROR_INVALID_FLAGS\n");  
    31.             break;  
    32.         case ERROR_INVALID_PARAMETER:  
    33.             printf("ERROR_INVALID_PARAMETER\n");  
    34.             break;  
    35.         case ERROR_NO_UNICODE_TRANSLATION:  
    36.             printf("ERROR_NO_UNICODE_TRANSLATION\n");  
    37.             break;  
    38.         }  
    39.     }  
    40.     else  
    41.     {  
    42.         cout<<"转换成功"<<endl;  
    43.         cout<<dBuf;   
    44.     }  
    45.   
    46.     delete(dBuf);  
    47. }  
    注意:两次调用MultiCharToWideChar()时,形参cchMultiByte的取值需要相同,否则可能会出现接收缓存不足之类的错误,从而导致转换失败!

     ( 2 ) 从宽字节转为窄字节字符串

    步骤与(1)类似,故不赘述

    代码示例如下:

    [cpp]  view plain  copy
    1. //从宽字符串转换窄字符串  
    2. wchar_t sBuf[25]={0};  
    3. wcscpy(sBuf, L"我最棒");  
    4.   
    5. //获取转换所需的目标缓存大小  
    6. DWORD dBufSize=WideCharToMultiByte(CP_OEMCP, 0, sBuf, -1, NULL,0,NULL, FALSE);  
    7.   
    8. //分配目标缓存  
    9. char *dBuf = new char[dBufSize];  
    10. memset(dBuf, 0, dBufSize);  
    11.   
    12. //转换  
    13. int nRet=WideCharToMultiByte(CP_OEMCP, 0, sBuf, -1, dBuf, dBufSize, NULL, FALSE);  
    14.   
    15. if(nRet<=0)  
    16. {  
    17.     printf("转换失败\n");  
    18. }  
    19. else  
    20. {  
    21.     printf("转换成功\nAfter Convert: %s\n", dBuf);  
    22. }  
    23. delete []dBuf;  

    三、MultiByteToWideChar()函数乱码的问题

    有的朋友可能已经发现,在标准的WinCE4.2或WinCE5.0 SDK模拟器下,这个函数都无法正常工作,其转换之后的字符全是乱码!

    及时更改MultiByteToWideChar()参数也依然如此。不过这个不是代码问题,其结症在于所定制的操作系统.如果我们定制的操作系统默认语言不是中文,也会出现这种情况。

    由于标准的SDK默认语言为英文,所以肯定会出现这个问题。而这个问题的解决,不能在简单地更改控制面板的"区域选项"的"默认语言",而是要在系统定制的时候,选择默认语言为"中文"。系统定制时选择默认语言的位置于:   Platform -> Setting... -> locale -> default language ,选择"中文",然后编译即可。






    展开全文
  • unicode和MBCS(多字节字符集)的关系

    千次阅读 2016-07-08 18:38:51
    目前Windows的内核已经支持Unicode字符集,这样在内核上可以支持全世界所有的语言文字。但是由于现有的 大量程序和文档都采用了某种特 定语言的编码,例如GBK ,Windows不可能不支持现有的编码,而全部改用Unicode。...
  • Visual Studio 2013默认使用unicode字符集,所以你会看到'W'或者'w'前缀(wchar,WCHAR等等)。 如果你在编译(旧版本启用了_MBCS的项目) 时 遇到这样的问题 Building an MFC project for a non-Unicode ...
  • 项目使用多字节字符集,cpp文件内代码,使生成的程序支持UTF8字符编码 文件内容如下: //////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////...
  • 多字节字符和宽字符

    千次阅读 2014-07-22 16:02:47
    多字节字符和宽字符 开发语言版软件,经常会碰到字符编码的问题,看了很资料都说得不是很清楚,终于碰到一篇讲的不错的文章跟大家分享一下!(时间关系,翻译了重点部分) char型和wchar型  在日文版Windows...
  • 第一个就是宽字符到多字节字符转换函数,函数原型如下: int WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int ...
  • void wchar2char()//宽字节字符串转多字节字符串 {  //该方法只能转英文和数字 int i; wchar_t *pwchello = L"Hello, world."; int nLen = wcslen(pwchello)+1;//13+1 char *pmbbuf = (char *)malloc(nLe
  • 多字节字符串转换为UNICODE字符串
  • Unicode字符与多字节字符的转换

    千次阅读 2011-03-09 10:13:00
    第一个就是宽字符到多字节字符转换函数,函数原型如下: <br />int WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, ...
  • 宽字符到多字节字符转换【精华】

    千次阅读 2012-12-05 16:49:56
    第一个就是宽字符到多字节字符转换函数,函数原型如下: int WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, ...
  • 宽字符到多字节字符转换函数

    千次阅读 2006-08-13 10:46:00
    近日闲来无事,前一阵子又被Unicode搞的焦头烂额,于是想看...第一个就是宽字符到多字节字符转换函数,函数原型如下:int WideCharToMultiByte(UINT CodePage,DWORD dwFlags,LPCWSTR lpWideCharStr,int cchWideCh
  • _T的意思是通知编译器,自行进行字符串的多字节/Unicode转换。 而L表示,该字符串为Unicode版本。 http://www.blogjava.net/neumqp/archive/2006/03/09/34504.html http://blog.csdn.net/sl159/articl
  • 2.LANG的常用设置,可以解决编译及系统显示信息的乱码问题,甚至有个别程式运行会出错,不过页面空白,显示不出信息,后台报xml解析的时候转换的某种错误,主要是字符集转换导致空值造成的。 LANG设置成:LANG=”...
  • 1.MySQL的字符集(character set)问题(乱码问题): 1.1 版本与字符集: ​ Mysql5.5版本在my.ini上上修改character-set-server为utf8 ​ Mysql8.0以上安装完默认character_set_server 为utf8mb4 ​ default-...
  • _T的意思是通知编译器,自行进行字符串的多字节/Unicode转换。 而L表示,该字符串为Unicode版本。http://www.blogjava.net/neumqp/archive/2006/03/09/34504.html http://blog.csdn.net/sl159/arti
  • --1,建包含clob列的表drop table t_test_clob;create table t_test_clob(a clob);insert into t_test_clob values('c...
  • 最近在开发中遇到了点Emoji相关的问题,便去了解了一下Emoji的编码规则,发现其中涉及了许多字符集字符集编码的知识点,便趁这个机会做一次这方面的总结梳理。本篇内容主要是对字符集字符集编码的知识整理。 1. ...
  • postgresql 关于GBK和utf-8字符集问题

    万次阅读 2018-01-09 22:21:34
    postgresql中没有GBK字符集。oracle有。 字符集之间的转换可以通过如下方式实现: convert(要转换的字符串, 目标字符集, 源字符集) 例如: highgo=# select convert('abcdefg', 'UTF8', 'GBK'); By 徐云鹤
  • MySQL原理 - 字符集与排序规则

    千次阅读 2020-06-11 17:51:02
    任何计算机存储数据,都需要字符集,因为计算机存储的数据其实都是二进制编码,将一个个字符,映射到对应的二进制编码的这个映射就是字符编码(字符集)。这些字符如何排序呢?决定字符排序的规则就是排序规则。 ...
  • 字符集设置问题深究

    千次阅读 2015-03-20 21:02:52
    字符集(Charset):是一个系统支持的所有抽象字符的集合。 字符编码(Character Encoding):是一套法则,描述字符集与数字系统之间建立对应关系。给定一系列字符,对每个字符赋予一个数值,用数值来代表对应的字符,...
  • Oracle:字符集查看与修改

    千次阅读 2018-04-07 21:20:07
    文章转自:http://blog.itpub.net/8475224/viewspace-692675/一、什么是Oracle字符集 Oracle字符集是一个字节数据的解释的符号集合,有大小之分,有相互的包容关系。ORACLE 支持国家语言的体系结构允许你使用本地化...
  • IOException parsing XML document from class path resource [spring-dao.xml]; nested exception is ...经过次探索将xml中的字符集格式由`encoding="UTF-8"`改为`encoding="UTF8"`竟然就
  • 以前我们习惯与用单字节字符集来编程.2 单字符集:将文本串作为一系列单字节字符来进行编码,并在结尾处放上一个零。(每个字符用一个字节来表示)3 双字节字符集(D B C S ):在双字节字符集中,字符串中的每个字符可以...
  • ORACLE如何修改字符集

    千次阅读 2019-01-22 09:46:04
    中文在ZHS16GBK中占2个字节,在UTF-8中却占3个字节,所以汉字导入UTF-8字符集的数据库就很容易出现字段长度不够,解决办法,一个是增加字段长度,还有就是修改字符集。 如果系统中已经存在很数据...
  • C++ 多字节与宽字符串的相互转换

    万次阅读 2015-11-28 11:46:41
    问题描述char字符与wchar_t字符由于编码不同,所以在char*和wchar_t*之间使用强制类型转换达不到正确转换字符串的目的。考察如下程序。#include &amp;amp;amp;amp;amp;amp;amp;amp;lt;iostream&amp;amp;amp;...
  • Oracle字符集、编码

    2015-04-29 22:58:49
    HANDBOOK系列之十:字符集、编码以及Oracle的那些事 第一部分字符集与编码常识 字符集: 人们根据需要把某些字符收集到一处,并赋以名称,于是便有了某某字符集。 编码: 当前面收集的工作完成以后,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 38,871
精华内容 15,548
关键字:

多字节字符集无效