编码问题一网打尽
字符集与编码问题小结
大部分内容copy自网络,我只是整理在一起 2012/10/11
编码的引入ASCII有人用 0x41 代表a,有人用 0x81 表示。语言不通,不同的计算机无法交流。美国人很早发现了这种问题,为便于交流指定了编码标准,于是有了:
ASCII(American Standard Code for Information)
ASCII码是7位编码,但由于计算机基本处理单位为字节(1byte = 8bit),所以一般仍以一个字节来存放一个ASCII字符。每一个字节中多余出来的一位(最高位)在计算机内部通常保持为0。
ASCII被定为国际标准之后的代号为ISO-646
ASCII 解决了美国人的问题,但很快,其他国家发现了这个编码不能满足自己国家的需要。法国、德国等国家暂且不说,英国都发现ASCII有问题:英镑符号“£”去哪儿了?现在好了,既想与ASCII兼容,有要添加ASCII没有的文字符号,怎么办?扩展一下吧!
由于ASCII码只使用了7个二进制位,也就是说一个字节可以表示的256个数字中,它仅使用了0~127这128个码位,剩下的128个码位便可以用来做扩展,用来表示一些特定语言所独有的字符
因此对这多余的128个码位的不同扩展,就形成了一系列ISO-8859-*的标准。例如为英语作了专门扩展的字符集编码标准编号为ISO-8859-1,也叫做Latin-1。
ISO-8859-*(*代表1~11,13~16)共15个编码方案,解决了拉丁字母的语言(主要是欧洲国家的语言),使用西里尔字母的东欧语言、希腊语、泰语、现代阿拉伯语、希伯来语等。
*这些编码方案在当时解决了这些国家的问题,但不同的编码如同军阀割据,同一势力范围内交流没问题,但不能普遍通用。比如 \xA3 在使用 Latin-1 的国家看来,是英镑符号“£”,而在使用 Latin-2的国家看来,却是另一个符号 “?”。而且无法在一个文件内同时出现这两个符号。这个问题的解决,需要unicode。
ISO-2022 与 EUC
ISO-8859-*解决了多数语言的编码问题,可是,汉语、日语及韩语字数众多,无法用单一个8位字符来表达,也就是无法通过类似 ISO-8859-*的方式解决。于是有了 ISO-2022。
ISO-2022提供了这样一种技术,它能在一种字符编码中支持多种字符集,可以用8位或16位来表示一个文字(字符),是一种变长的编码,这样,就能表示中日韩的字符了。该编码还有个显著的特点,就是所有的字节都是以0开始的。
ISO-2022在日本用的比较普遍,在中国反倒是很少使用。尽管如此,还是用中文的ISO-2022-CN 简单说一下:
在继续之前,我们先提下GB2312:GB2312 中规定了汉字的区位码(对应的二进制表,可以看做后面说的编码方案)。那么,如果指定 ISO-2022 (等同GB 2311) 作为为其包装方式(用来避免和ASCII的冲突)。
这里不得不介绍下ASCII控制字符了,既ASCII的0-31位表示其实都不是字符的编码而是用作它途
附上一张表:
0 0x00 NUL空
11 0x0b VT垂直制表
22 0x16 SYN空转同步
1 0x01 SOH标题开始
12 0x0c FF走纸控制
23 0x17 ETB信息组传送结束
2 0x02 STX正文开始
13 0x0d CR回车
24 0x18 CAN作废
3 0x03 ETX正文结束
14 0x0e SO移位输出
25 0x19 EM纸尽
4 0x04 EOY传输结束
15 0x0f SI移位输入
26 0x1a SUB换置
5 0x05 ENQ询问字符
16 0x10 DLE空格
27 0x1b ESC换码
6 0x06 ACK承认
17 0x11 DC1设备控制1
28 0x1c FS文字分隔符
7 0x07 BEL报警
18 0x12 DC2设备控制2
29 0x1d GS组分隔符
8 0x08 BS退一格
19 0x13 DC3设备控制3
30 0x1e RS记录分隔符
9 0x09 HT横向列表
20 0x14 DC4设备控制4
31 0x1f US单元分隔符
10 0x0a LF换行
21 0x15 NAK否定
127 0xff DEL删除
汉字“文”字在46区36位,然后用 ISO 2022 包装时,字节序列是:
<ESC>$ ) A <SO> <0x4E> <0x44> <SI>
ISO2022使用“逃逸字串”(Escape sequence)。逃逸字串由1个“ESC”字符(0x1B),再由两至三个字串组成。此标记代表它后面的字符,属于下表字符集的文字。
<ESC> 是字节 0x1b,表示换码
然后ESC $ ) A 转为GB2312-1980 (2 bytes per character)
<SO> 是字节 0x0e,表示脱离普通 ASCII 编码模式,进入特殊编码模式(这儿进入的是 GB 2312-1980 编码方式)
<SI> 是字节 0x0f,表示返回普通 ASCII 编码模式
第一字节 0x4E 是在区号 46 的基础上加上32,以避开 ASCII 的控制符区(<32)
第二字节 0x44 是在位号 36 的基础上加上32,以避开 ASCII 的控制符区(<32)
ISO/IEC2022 - Wikipedia, the free encyclopedia
前面说了,ISO-2022-CN 在国内很少使用,那么国内用的什么编码方案呢?
那就是 EUC-CN:
EUC(Extended Unix Code),是一个主要用于日文、韩文、简体中文的多字节编码系统,它基于ISO-2020标准。
它使用了一些兼容于ISO-2022区位码的94x94编码表,把每个区位加上0xA0来表示,以便兼容于ASCII。
今天通常说的 GB2312 编码都是指 EUC(ISO-2020) 包装的GB2312 编码。
Extended Unix Code - Wikipedia, thefree encyclopedia
EUC-GB2312 与区位码的关系:
第1字节 = 区码 + 32 + 0x80
第2字节 = 位码 + 32 + 0x80
所以,“文”字的 EUC-GB2312 编码是 0xCE 0xC4,用记事本保存一个“文”,然后用FlexHex查看
当然,大端小端问题和BOM一起说。
Unicode
Unicode是由于传统的字符编码方式的局限性而产生的,例如:
ISO8859所定义的字符虽然在不同的国家中广泛地使用,可是在不同国家间却经常出现不相容的情况。
很多传统的编码方式都具有一个共通的问题,即其容许电脑进行双语环境式的处理(通常是ASCII以及其本地语言),但却无法同时支援多语言环境式的处理(比如同是处理中文和日文)。
于是一个将所有国家所有语种的所有文字进行统一编码的方案开始了...
Unicode与UCS1980年代,有两个组织分别开始开发适用于各国语言的通用码,但不久他们便发现了对方的存在。
Unicode组织,由多家计算机软件公司,还包括一些出版行业的公司共同发起的。采用16位编码空间。
ISO-10646项目组,UniversalCharacter Set(UCS),采用31位编码空间。
ISO与Unicode是两个不同的组织,因此最初制定了不同的标准;但自从unicode2.0开始,unicode采用了与ISO 10646-1相同的字库和字码,ISO也承诺ISO10646将不会给超出0×10FFFF的UCS-4编码赋值,使得两者保持一致。
最终,两者统一了抽象字符集(即任何一个在Unicode中存在的字符,在UCS中也存在),且最靠前的65535个字符也统一了字符的编码。
现在可以认为UCS和UNICODE是一个概念。
字符编码方案在传统意义上,没有字符集和编码的区分,比如GB2312、Latin1等都是既指代字符集又指代编码方案。
编码字符集 CodedCharacter Set
字符编码 CharacterEncoding
按照惯例,人们认为字符集和字符编码是同义词,但现代的编码方案 Unicode,没有遵循这种惯例。
Unicode 是一个字符集合,它给集合中的每个字符都指定一了个代号code point。
字符到代号的过程。更简单的说就是指Unicode字符平面映射.(U+0000~ U+FFFF 这个序列中,每一个代号对应一个字符,不同的字符在字符平面上都有其对应的代号)
当我们要把这个代号存到计算机中时,需要把它变成一个字节的序列。
代号如果转换成到机器序列(机器编码)呢?这个过程有些可能为了节省空间而修改一些内容(utf8,utf16)...
于是不同的变换方式引入了:
小结一下:
Unicode是规范,是编码字符集,规定了字符到字符平面代号的映射关系,其有UCS2和UCS4两种格式。UCS2和UCS4都是定长的,而不是字符编码方案。
UTF是Unicode Transformation Format,是Unicode的实现,是字符编码方案,规定了字符平面代号到机器编码(保存传输)的关系。
它分为utf-8,utf-16,utf-32几种形式,其中utf-8和utf-16都是变长的,而utf-32是定长编码。(其实还有utf-7等其它编码存在)
基本上可以理解为UTF-32就是UCS4,而UTF-16和UCS2兼容,只是UTF-16扩展了一些。
UTFUTF-8,8bit编码, ASCII不作变换, 其他字符做变长编码, 每个字符1-6 byte. 通常作为外码.
有以下优点:
1.与CPU字节顺序无关, 可以在不同平台之间交流
2.容错能力高, 任何一个字节损坏后, 最多只会导致一个编码码位损失, 不会链锁错误(如GB码错一个字节就会整行乱码)
UTF-8用一个字节表示ASCI字符,用两个字节表示西欧字符,用三个字符表示亚洲的大部分字符。
UTF-16,16bit编码, 是变长码, UTF-16则是unicode的preferred encoding。
UCS-2与UTF-16在对前65536个字符的处理上完全相同,唯一的区别只在于 UCS-2 不支持surrogate pair机制,即是说,UCS-2只能对前65536个字符编码,对其后的字符毫无办法。
UTF-16是windows平台上主要使用的编码方案,一般windows上所说的UNICODE就是指它了.
UTF-32,仅使用了unicode范围(0到0x10FFFF)的32位编码, 相当于UCS-4的子集.
BOM
UTF还涉及到字节序的问题。字节顺序标记(Byte Order Mark, 简称BOM)出现在Unicode流开端,说明编码类型。BOM是一个有点小聪明的想法。
关于字节序问题。例如“奎”的Unicode编码是U+594E,“乙”的Unicode编码是U+4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?
Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill OfMaterial”的BOM表,而是Byte OrderMark。BOM是一个有点小聪明的想法:
在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是0xFEFF。(标准其实算是Big Endian的)
Zero-widthnon-breaking space (ZWNBSP) is a deprecated use of the Unicode character atcode point U+FEFF. Character U+FEFF is intended for use as a Byte Order Markat the start of a file. However, if encounteredelsewhere it should, according to Unicode, be treated as a "zero-widthnon-breaking space". The deliberate use of U+FEFF for this purpose is nowdeprecated, with U+2060 word joiner (HTML: ⁠) strongly preferred.
而不同的编码方案解析这个"ZERO WIDTH NO-BREAKSPACE"字符 时就会产生不同的结果:
编码方式
big endian
little endian
UTF-16 big endian
FE FF
FF FE(Windows)
UTF-32 bign endian
00 00 FE FF
FF FE 00 00
UTF-8 little endian (gcc)
EF BB BF
EF BB BF
由于utf-8的big endian和littleendian结果都是一样的,linux下就默认不需要BOM,而Windows下默认没有BOM的文本是DBCS编码(GBK),所以Windows下如果要使用utf-8的话就需要带上BOM了,这是一个不兼容的地方,linux下如果带上utf-8的BOM就会报错。
注意:在UCS中是不存在的"U+FFFE" code point的,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。
这样传输Unicode字符时,如果接收者收到FEFF,就表明他是utf-16,并且它的字节序是Big-Endian的;如果是FFFE,就表明字节序是Little-Endian的。
因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。我们可以在保存和读取文本文件时用到它。
GB18030GB18030: Unicode 的GBK扩展版本, 覆盖了所有unicode编码, 地位等同于UTF-8, UTF-16, 是一种unicode编码形式. 变长编码, 用单字节/双字节/4字节对字符编码
GB18030向下兼容GB2312/GBK.
GB18030 是中国所有非手持/嵌入式计算机系统的强制实施标准.
base64Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一
Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,可以估算编码后数据长度大约为原长的135.1%。
ASCII中有很多字符是不可打印的,26个英文字母大小写加上0~9已经有62个字符了,再加上"+"和"/"正好凑了64和字符
base64可以用来将二进制的字节序列数据编码成ASCII字符序列构成的文本,也就是说图片之类的也可以用base64直接编码.
HZ将 EUC-GB2312 的各字节最高位去掉,再在前后分别加上转义字符,
例如“文”:
~{<0x4E> <0x44> ~}
源文件内的编码与执行时字符编码我们先列个表,看看两种乱码分别在那种情况下出现:
我们只列举大家最常用的3个编译器(微软VS的中的cl,Mingw中的g++,Linux下的g++),源代码分别采用 GBK 和 不带BOM的UTF-8 以及 带BOM的UTF-8 这3中编码进行保存。
源代码的编码
编译器
结果
GBK
cl
1
*
mingw-g++
1
*
g++
1
UTF-8(不带BOM)
cl
2
mingw-g++
2
g++
2
*
UTF-8(带BOM)
cl
1
mingw-g++
2
g++
编译失败
采用3种不同编码保存的源代码文件,分别用3种不同的编译器编译,形成9种组合,除掉一种不能工作的情况,两种乱码出现的情况各占一半。
从中我们也可以看出,乱码和操作系统原本是没有关系的。
但我们在 Windows 一般用的GBK,linux一般用的是不带BOM的UTF-8。
如果我们只考虑带*的情况,也可以说两种乱码和系统有关。
默认情况下
源文件编码
编译器
"我是中文" 内存中编码
GBK
cl
成功转成Unicode
gcc
失败,编译不过
UTF8(带BOM)
cl
成功
gcc
成功
UTF8(不带BOM)
cl
失败,输出乱码
gcc
成功
对 cl
只要源代码带BOM,如果源代码有BOM,对于不带L的字符串,直接转GBK。
猜想:对于带L的字符串,直接转ucs2?
如果不带BOM,编译器默认源代码文本是gbk编码,再进行相关的转换。
于是,当我们用不带BOM的utf8格式时,cl将其按照gbk解码。
对 gcc
默认将所有的字符串都按照utf8解码。带不带utf8的BOM都不影响。
其实gcc是支持其他编码的,只不过需要通过编译选项来指定。比如对gbk:gcc main.c-finput-charset=gbk -o main
VS2010如果源码文件不带BOM的话,是不自动转换编码的,直接使用源码中的编码。使用BOM则会自动转换成GBK编码。
要禁止编码自动转换成GBK,可以加一个指令,更改执行字符集:
#pragmaexecution_character_set("UTF-8")
上面提到的是"文件保存时需要BOM",也就是它需要知道"源码文件的编码",才能知道如何转换成"执行时字符集"。可以想到,一旦去掉BOM后,cl编译器只能靠猜测,这是不可靠的。
// 下面的代码在简体中文Windows下的MVSC2010下,无法通过编译
// 说明windows下源代码保存需要BOM,不带BOM直接当做GBK
// utf8 encoded c++ source file without BOM
#include<iostream>
int main()
{
std::cout<<sizeof("不带BOM是不给转换编码的,而使用了BOM后,会自动将UTF-8编码转换成GBK。");
return0;
}
但是 目前GCC编译器不接受带有BOM的源代码文件,而且Linux/UNIX 并没有使用 BOM,因为它会破坏现有的 ASCII 文件的语法约定,所以问题应该还只是部分解决。
再来说一说CodePage
代码页 - 维基百科,自由的百科全书
在1980年前,仍然没有任何国际标准如ISO-8859或Unicode来定义如何扩展US-ASCII编码以便非英语国家的用户使用.于是很多IT 厂商发明了他们自己的编码,并且使用了难以记忆的数目来标识: ISO-8859-*,ISO-2022 与 EUC,…
代码页是字符集编码的别名,也称"内码表",是特定语言的字符集的一张表。早期,代码页是IBM称呼计算机的BIOS所支持的字符集编码。当时通用的操作系统都是命令行界面,这些操作系统直接使用BIOS提供的字符绘制功能来显示字符。这些BIOS代码页也被称为OEM代码页。图形操作系统使用自己的字符呈现引擎(rendering engine),可以支持多个不同的字符集编码,这类代码页被称作ASCII代码页。
早期IBM和微软内部使用数字来标记不同的编码字符集,不同的厂商对同一个字符集编码使用各自不同的名称。例如,UTF-8在IBM称作代码页1208, 在微软称作代码页65001, 在SAP称作代码页4110.
1987年4月,IBM发布了PC-DOS 3.3,正式开始使用16比特的无符号整数标识不同的代码页。这时的PC机使用CGA显示系统的字符界面,绘制不同语言的字符依靠BIOS硬件厂商提供的功能。如果想更换所支持的字符集,就必须换上支持该字符集的ROM芯片。微软作为DOS操作系统的软件厂商,并不拥有绘制这些字符集的知识产权。所以这些字符集的绘制实现,称作OEM代码页。最常见、最具代表性的OEM代码页是"IBM PC或MS-DOS 代码页437"。
随着图形用户界面操作系统的广泛使用(最初被广为接受的是Windows 3.1),操作系统具有了字符绘制的功能。微软在Windows操作系统没有转向UTF-16作为内码实现之前(也就是在Windows 2000之前),针对不同的使用地区与国家,定义了一系列的支持不同语言字符集的代码页,被称作"Windows (或ANSI) 代码页"。代表性的是实现了ISO-8859-1的代码页1252.
要使用CodePage的原因还有,很多符号形状(字体)的映射都是基于本地方案,既不是unicode字体。(个人猜测)
字符内码(charcter code)指的是用来代表字符的内码.读者在输入和存储文档时都要使用内码,内码分为
单字节内码 -- Single-Byte character sets (SBCS),可以支持256个字符编码.
双字节内码 -- Double-Byte character sets)(DBCS),可以支持65000个字符编码.主要用来对大字符集的东方文字进行编码.
codepage指的是一个经过挑选的以特定顺序排列的字符内码列表,对于早期的单字节内码的语种,codepage中的内码顺序使得系统可以按照此列表来根据键盘的输入值给出一个对应的内码.对于双字节内码,则给出的是MultiByte到Unicode的对应表,这样就可以把以Unicode形式存放的字符转化为相应的字符内码,或者反之,在Linux核心中对应的函数就是utf8_mbtowc和utf8_wctomb.
现在来看这些Codpage 是不是很容易理解了?
中日韩 Codepage同 Extended Unix Coding ( EUC )编码大不一样的是,下面所有的远东 codepage 都利用了C1控制码{ 80.9F } 做为首字节, 使用ASCII值 { =407E { 做为第二字节,这样才能包含多达数万个双字节字符,这表明在这种编码之中小于3F的ASCII值不一定代表ASCII字符.
CP932Shift-JIS包含日本语 charset JIS X 0201 (每个字符一个字节) 和 JIS X 0208 (每个字符两个字节),所以 JIS X 0201平假名包含一个字节半宽的字符,其剩馀的60个字节被用做7076个汉字以及648个其他全宽字符的首字节.同EUC-JP编码区别的是,Shift-JIS没有包含JIS X 202中定义的5802个汉字.
CP936GBK扩展了 EUC-CN 编码( GB 2312-80编码,包含 6763 个汉字)到Unicode (GB13000.1-93)中定义的20902个汉字,中国大陆使用的是简体中文zh_CN.
CP949UnifiedHangul(UHC) 是韩文 EUC-KR 编码(KS C 5601-1992 编码,包括2350 韩文音节和 4888 个汉字a)的超集,包含 8822个附加的韩文音节( 在C1中 )
CP950是代替EUC-TW (CNS 11643-1992)的 Big5 编码(13072 繁体 zh_TW 中文字)繁体中文,这些定义都在Ken Lunde的 CJK.INF中或者 Unicode 编码表中找到.
特别的:和Unicode相关的CodePage
CP1200 — UCS-2LE Unicode 小端序
CP1201 — UCS-2BE Unicode 大端序
CP65000 — UTF-7 Unicode
CP65001 — UTF-8 Unicode
Linux下Codepage在Linux下引入对Codepage的支持主要是为了访问FAT/VFAT/FAT32/NTFS/NCPFS等文件系统下的多语种文件名的问题,目前在NTFS和FAT32/VFAT下的文件系统上都使用了Unicode,这就需要系统在读取这些文件名时动态将其转换为相应的语言编码.因此引入了NLS支持.其相应的程序文件在/usr/src/linux/fs/nls下:
Config.in,Makefile ,nls_base.c ,nls_cp437.c ,nls_cp737.c ,nls_cp775.c ,nls_cp850.c ,nls_cp852.c ,nls_cp855.c ,nls_cp857.c ,nls_cp860.c ,nls_cp861.c ,nls_cp862.c ,nls_cp863.c ,nls_cp864.c ,nls_cp865.c ,nls_cp866.c ,nls_cp869.c ,nls_cp874.c ,nls_cp936.c ,nls_cp950.c ,nls_iso8859-1.c ,nls_iso8859-15.c ,nls_iso8859-2.c ,ls_iso8859-3.c ,nls_iso8859-4.c ,nls_iso8859-5.c ,,nls_iso8859-6.c ,nls_iso8859-7.c ,nls_iso8859-8.c ,nls_iso8859-9.c ,nls_koi8-r.c
实现了下列函数:
extern int utf8_mbtowc(__u16*,const __u8*,int);
extern int utf8_mbstowcs(__u16*,const __u8*,int);
extern int utf8_wctomb(__u8*, __u16,int);
extern int utf8_wcstombs(__u8*,const __u16*,int);
这样在加载相应的文件系统时就可以用下面的参数来设置Codepage:
对于Codepage 437 来说
mount-t vfat /dev/hda1 /mnt/1 -o codepage=437,iocharset=cp437
这样在Linux下就可以正常访问不同语种的长文件名了.
利用iconv函数族进行编码转换
#include<iconv.h>
#pragma comment(lib,"iconv.lib")
int code_convert(char*from_charset,char*to_charset,constchar*inbuf, size_t inlen,char*outbuf, size_t outlen)
{
iconv_t cd;
constchar**pin=&inbuf;
char**pout=&outbuf;
cd =iconv_open(to_charset,from_charset);
if (cd==0)
return-1;
memset(outbuf,0,outlen);
if (iconv(cd, pin,&inlen,pout,&outlen)==-1)
return-1;
iconv_close(cd);
return0;
}
/* UTF-8 to GBK */
int u2g(constchar*inbuf, size_t inlen, char*outbuf, size_t outlen)
{
return code_convert("UTF-8","GBK",inbuf,inlen,outbuf,outlen);
}
/* GBK to UTF-8 */
int g2u(constchar*inbuf, size_t inlen, char*outbuf, size_t outlen)
{
return code_convert("GBK","UTF-8", inbuf, inlen, outbuf, outlen);
}
用于char_set的参数列表
European languages
ASCII, ISO-8859-{1,2,3,4,5,7,9,10,13,14,15,16}, KOI8-R, KOI8-U, KOI8-RU,CP{1250,1251,1252,1253,1254,1257}, CP{850,866,1131}, Mac{Roman,CentralEurope,Iceland,Croatian,Romania}, Mac{Cyrillic,Ukraine,Greek,Turkish}, Macintosh
Semitic languages
ISO-8859-{6,8}, CP{1255,1256}, CP862, Mac{Hebrew,Arabic}
Japanese
EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP, ISO-2022-JP-2, ISO-2022-JP-1
Chinese
EUC-CN, HZ, GBK, CP936, GB18030, EUC-TW,BIG5, CP950, BIG5-HKSCS, BIG5-HKSCS:2001, BIG5-HKSCS:1999, ISO-2022-CN, ISO-2022-CN-EXT
Korean
EUC?KR, CP949, ISO?2022?KR, JOHAB
Armenian
ARMSCII-8
Georgian
Georgian-Academy, Georgian-PS
Tajik
KOI8-T
Kazakh
PT154, RK1048
Thai
TIS-620, CP874, MacThai
Laotian
MuleLao-1, CP1133
Vietnamese
VISCII, TCVN, CP1258
Platform specifics
HP-ROMAN8, NEXTSTEP
Full Unicode
UTF-8,UCS-2, UCS-2BE,UCS-2LE,UCS-4, UCS-4BE, UCS-4LE,UTF-16, UTF-16BE, UTF-16LE,UTF-32, UTF-32BE, UTF-32LE,UTF-7,C99,JAVA
Full Unicode, in terms of uint16_t or uint32_t
UCS-2-INTERNAL, UCS-4-INTERNAL
(with machine dependent endianness and alignment)
Locale dependent, in terms of char or wchar_t
char, wchar_t
(with machine dependent endianness and alignment, and with semantics depending on the OS and the current LC_CTYPE locale facet)
When configured with the option --enable-extra-encodings,
it also provides support for a few extra encodings:
European languages
CP{437,737,775,852,853,855,857,858,860,861,863,865,869,1125}
Semitic languages
CP864
Japanese
EUC-JISX0213, Shift_JISX0213, ISO-2022-JP-3
Chinese
BIG5-2003 (experimental)
Turkmen
TDS565
Platform specifics
ATARIST, RISCOS-LATIN1
The empty encoding name "" is equivalent to"char":
it denotes the locale dependent character encoding.
Windows下的编码转换
int ToUCS(unsignedchar*p,wchar_t* pUCS,int codepage)
{
int len=0;
if(pUCS== NULL|| p == NULL)
return-1;
len =MultiByteToWideChar(codepage,0,p,-1,NULL,0);
MultiByteToWideChar(codepage,0,p,-1,pUCS,len);
return len;
}
int UCSTo(wchar_t* pUCS,char*p,int codepage)
{
int len=0;
if(pUCS== NULL|| pBIG5 == NULL)
return-1;
len =WideCharToMultiByte(codepage,0,pUCS,-1,NULL,0,NULL,NULL);
WideCharToMultiByte(codepage,0,pUCS,-1,p,len,NULL,NULL);
len--;
return len;
}
WINBASEAPI int WINAPI
MultiByteToWideChar(
__in UINT CodePage,
__in DWORD dwFlags,
__in_bcount(cbMultiByte) LPCSTR lpMultiByteStr,
__in int cbMultiByte,
__out_ecount_opt(cchWideChar) __transfer(lpMultiByteStr) LPWSTR lpWideCharStr,
__in int cchWideChar);
WINBASEAPI int WINAPI
WideCharToMultiByte(
__in UINT CodePage,
__in DWORD dwFlags,
__in_ecount(cchWideChar) LPCWSTR lpWideCharStr,
__in int cchWideChar,
__out_bcount_opt(cbMultiByte) __transfer(lpWideCharStr) LPSTR lpMultiByteStr,
__in int cbMultiByte,
__in_opt LPCSTR lpDefaultChar,
__out_opt LPBOOL lpUsedDefaultChar);
codepage在MSDN定义如下
Bit
Code page
Description
ANSI
0
1252
Latin 1
1
1250
Latin 2: Eastern Europe
2
1251
Cyrillic
3
1253
Greek
4
1254
Turkish
5
1255
Hebrew
6
1256
Arabic
7
1257
Baltic
8
1258
VietNam
9 - 15
Reserved for ANSI
ANSI and OEM
16
874
Thai
17
932
Japanese, Shift-JIS
18
936
Chinese: Simplified chars—PRC and Singapore
ASCII、GB2312、GBK到GB18030 兼容
19
949
Korean Unified Hangeul Code (Hangeul TongHabHyung Code)
20
950
Chinese: Traditional chars—Hong Kong SAR, PRC and Taiwan
BIG5
21
1361
Korean (Johab)
22 - 29
Reserved for alternate ANSI and OEM
30 - 31
Reserved by system.
OEM
32 - 46
Reserved for OEM
47
1258
VietNam
48
869
IBM Greek
49
866
MS-DOS Russian
50
865
MS-DOS Nordic
51
864
Arabic
52
863
MS-DOS Canadian French
53
862
Hebrew
54
861
MS-DOS Icelandic
55
860
MS-DOS Portuguese
56
857
IBM Turkish
57
855
IBM Cyrillic; primarily Russian
58
852
Latin 2
59
775
Baltic
60
737
Greek; former 437 G
61
708
Arabic; ASMO 708
62
850
Western European/Latin 1
63
437
US
利用ICU进行编码转换
IBM Globalization -ICU
#include<unicode/ucnv.h>
#ifdef _WIN32
#pragmacomment(lib,"icuuc.lib")
#endif
//返回0为成功,错误代码定义见后面
intconvert(constchar* toConverterName,
constchar* fromConverterName,
char* target,
int32_t targetCapacity,
constchar* source,
int32_t sourceLength)
{
UErrorCode errorcode= U_ZERO_ERROR;
ucnv_convert(toConverterName,fromConverterName,target, targetCapacity, source, sourceLength,&errorcode );
return errorcode;
}
int _tmain(int argc, _TCHAR* argv[])
{
wchar_t aaa[]= L"中国人的系统上123323";
int alen= wcslen(aaa);
int blen=alen*2+sizeof(int);
char*abuff=newchar[blen];
int result= convert("gb2312", "utf-16le", abuff, blen, (constchar*)aaa, alen);
cout<< abuff<< endl<<strlen(abuff)<<endl;
delete []abuff;
return0;
}
typedef enum UErrorCode{
/* The ordering of U_ERROR_INFO_START Vs U_USING_FALLBACK_WARNING looks weird
* and is that way because VC++ debugger displays first encountered constant,
* which is not the what the code is used for
*/
U_USING_FALLBACK_WARNING = -128, /**< A resource bundle lookup returned a fallback result (not an error) */
U_ERROR_WARNING_START = -128, /**< Start of information results (semantically successful) */
U_USING_DEFAULT_WARNING = -127, /**< A resource bundle lookup returned a result from the root locale (not an error) */
U_SAFECLONE_ALLOCATED_WARNING = -126, /**< A SafeClone operation required allocating memory (informational only) */
U_STATE_OLD_WARNING = -125, /**< ICU has to use compatibility layer to construct the service. Expect performance/memory usage degradation. Consider upgrading */
U_STRING_NOT_TERMINATED_WARNING = -124,/**< An output string could not be NUL-terminated because output length==destCapacity. */
U_SORT_KEY_TOO_SHORT_WARNING = -123, /**< Number of levels requested in getBound is higher than the number of levels in the sort key */
U_AMBIGUOUS_ALIAS_WARNING = -122, /**< This converter alias can go to different converter implementations */
U_DIFFERENT_UCA_VERSION = -121, /**< ucol_open encountered a mismatch between UCA version and collator image version, so the collator was constructed from rules. No impact to further function */
U_PLUGIN_CHANGED_LEVEL_WARNING = -120, /**< A plugin caused a level change. May not be an error, but later plugins may not load. */
U_ERROR_WARNING_LIMIT, /**< This must always be the last warning value to indicate the limit for UErrorCode warnings (last warning code +1) */
U_ZERO_ERROR = 0, /**< No error, no warning. */
U_ILLEGAL_ARGUMENT_ERROR = 1, /**< Start of codes indicating failure */
U_MISSING_RESOURCE_ERROR = 2, /**< The requested resource cannot be found */
U_INVALID_FORMAT_ERROR = 3, /**< Data format is not what is expected */
U_FILE_ACCESS_ERROR = 4, /**< The requested file cannot be found */
U_INTERNAL_PROGRAM_ERROR = 5, /**< Indicates a bug in the library code */
U_MESSAGE_PARSE_ERROR = 6, /**< Unable to parse a message (message format) */
U_MEMORY_ALLOCATION_ERROR = 7, /**< Memory allocation error */
U_INDEX_OUTOFBOUNDS_ERROR = 8, /**< Trying to access the index that is out of bounds */
U_PARSE_ERROR = 9, /**< Equivalent to Java ParseException */
U_INVALID_CHAR_FOUND = 10, /**< Character conversion: Unmappable input sequence. In other APIs: Invalid character. */
U_TRUNCATED_CHAR_FOUND = 11, /**< Character conversion: Incomplete input sequence. */
U_ILLEGAL_CHAR_FOUND = 12, /**< Character conversion: Illegal input sequence/combination of input units. */
U_INVALID_TABLE_FORMAT = 13, /**< Conversion table file found, but corrupted */
U_INVALID_TABLE_FILE = 14, /**< Conversion table file not found */
U_BUFFER_OVERFLOW_ERROR = 15, /**< A result would not fit in the supplied buffer */
U_UNSUPPORTED_ERROR = 16, /**< Requested operation not supported in current context */
U_RESOURCE_TYPE_MISMATCH = 17, /**< an operation is requested over a resource that does not support it */
U_ILLEGAL_ESCAPE_SEQUENCE = 18, /**< ISO-2022 illlegal escape sequence */
U_UNSUPPORTED_ESCAPE_SEQUENCE = 19, /**< ISO-2022 unsupported escape sequence */
U_NO_SPACE_AVAILABLE = 20, /**< No space available for in-buffer expansion for Arabic shaping */
U_CE_NOT_FOUND_ERROR = 21, /**< Currently used only while setting variable top, but can be used generally */
U_PRIMARY_TOO_LONG_ERROR = 22, /**< User tried to set variable top to a primary that is longer than two bytes */
U_STATE_TOO_OLD_ERROR = 23, /**< ICU cannot construct a service from this state, as it is no longer supported */
U_TOO_MANY_ALIASES_ERROR = 24, /**< There are too many aliases in the path to the requested resource.
It is very possible that a circular alias definition has occured */
U_ENUM_OUT_OF_SYNC_ERROR = 25, /**< UEnumeration out of sync with underlying collection */
U_INVARIANT_CONVERSION_ERROR = 26, /**< Unable to convert a UChar* string to char* with the invariant converter. */
U_INVALID_STATE_ERROR = 27, /**< Requested operation can not be completed with ICU in its current state */
U_COLLATOR_VERSION_MISMATCH = 28, /**< Collator version is not compatible with the base version */
U_USELESS_COLLATOR_ERROR = 29, /**< Collator is options only and no base is specified */
U_NO_WRITE_PERMISSION = 30, /**< Attempt to modify read-only or constant data. */
U_STANDARD_ERROR_LIMIT, /**< This must always be the last value to indicate the limit for standard errors */
/*
* the error code range 0x10000 0x10100 are reserved for Transliterator
*/
U_BAD_VARIABLE_DEFINITION=0x10000,/**< Missing '</p> or duplicate variable name */
U_PARSE_ERROR_START = 0x10000, /**< Start of Transliterator errors */
U_MALFORMED_RULE, /**< Elements of a rule are misplaced */
U_MALFORMED_SET, /**< A UnicodeSet pattern is invalid*/
U_MALFORMED_SYMBOL_REFERENCE, /**< UNUSED as of ICU 2.4 */
U_MALFORMED_UNICODE_ESCAPE, /**< A Unicode escape pattern is invalid*/
U_MALFORMED_VARIABLE_DEFINITION, /**< A variable definition is invalid */
U_MALFORMED_VARIABLE_REFERENCE, /**< A variable reference is invalid */
U_MISMATCHED_SEGMENT_DELIMITERS, /**< UNUSED as of ICU 2.4 */
U_MISPLACED_ANCHOR_START, /**< A start anchor appears at an illegal position */
U_MISPLACED_CURSOR_OFFSET, /**< A cursor offset occurs at an illegal position */
U_MISPLACED_QUANTIFIER, /**< A quantifier appears after a segment close delimiter */
U_MISSING_OPERATOR, /**< A rule contains no operator */
U_MISSING_SEGMENT_CLOSE, /**< UNUSED as of ICU 2.4 */
U_MULTIPLE_ANTE_CONTEXTS, /**< More than one ante context */
U_MULTIPLE_CURSORS, /**< More than one cursor */
U_MULTIPLE_POST_CONTEXTS, /**< More than one post context */
U_TRAILING_BACKSLASH, /**< A dangling backslash */
U_UNDEFINED_SEGMENT_REFERENCE, /**< A segment reference does not correspond to a defined segment */
U_UNDEFINED_VARIABLE, /**< A variable reference does not correspond to a defined variable */
U_UNQUOTED_SPECIAL, /**< A special character was not quoted or escaped */
U_UNTERMINATED_QUOTE, /**< A closing single quote is missing */
U_RULE_MASK_ERROR, /**< A rule is hidden by an earlier more general rule */
U_MISPLACED_COMPOUND_FILTER, /**< A compound filter is in an invalid location */
U_MULTIPLE_COMPOUND_FILTERS, /**< More than one compound filter */
U_INVALID_RBT_SYNTAX, /**< A "::id" rule was passed to the RuleBasedTransliterator parser */
U_INVALID_PROPERTY_PATTERN, /**< UNUSED as of ICU 2.4 */
U_MALFORMED_PRAGMA, /**< A 'use' pragma is invlalid */
U_UNCLOSED_SEGMENT, /**< A closing ')' is missing */
U_ILLEGAL_CHAR_IN_SEGMENT, /**< UNUSED as of ICU 2.4 */
U_VARIABLE_RANGE_EXHAUSTED, /**< Too many stand-ins generated for the given variable range */
U_VARIABLE_RANGE_OVERLAP, /**< The variable range overlaps characters used in rules */
U_ILLEGAL_CHARACTER, /**< A special character is outside its allowed context */
U_INTERNAL_TRANSLITERATOR_ERROR, /**< Internal transliterator system error */
U_INVALID_ID, /**< A "::id" rule specifies an unknown transliterator */
U_INVALID_FUNCTION, /**< A "&fn()" rule specifies an unknown transliterator */
U_PARSE_ERROR_LIMIT, /**< The limit for Transliterator errors */
/*
* the error code range 0x10100 0x10200 are reserved for formatting API parsing error
*/
U_UNEXPECTED_TOKEN=0x10100, /**< Syntax error in format pattern */
U_FMT_PARSE_ERROR_START=0x10100, /**< Start of format library errors */
U_MULTIPLE_DECIMAL_SEPARATORS, /**< More than one decimal separator in number pattern */
U_MULTIPLE_DECIMAL_SEPERATORS = U_MULTIPLE_DECIMAL_SEPARATORS, /**< Typo: kept for backward compatibility. Use U_MULTIPLE_DECIMAL_SEPARATORS */
U_MULTIPLE_EXPONENTIAL_SYMBOLS, /**< More than one exponent symbol in number pattern */
U_MALFORMED_EXPONENTIAL_PATTERN, /**< Grouping symbol in exponent pattern */
U_MULTIPLE_PERCENT_SYMBOLS, /**< More than one percent symbol in number pattern */
U_MULTIPLE_PERMILL_SYMBOLS, /**< More than one permill symbol in number pattern */
U_MULTIPLE_PAD_SPECIFIERS, /**< More than one pad symbol in number pattern */
U_PATTERN_SYNTAX_ERROR, /**< Syntax error in format pattern */
U_ILLEGAL_PAD_POSITION, /**< Pad symbol misplaced in number pattern */
U_UNMATCHED_BRACES, /**< Braces do not match in message pattern */
U_UNSUPPORTED_PROPERTY, /**< UNUSED as of ICU 2.4 */
U_UNSUPPORTED_ATTRIBUTE, /**< UNUSED as of ICU 2.4 */
U_ARGUMENT_TYPE_MISMATCH, /**< Argument name and argument index mismatch in MessageFormat functions */
U_DUPLICATE_KEYWORD, /**< Duplicate keyword in PluralFormat */
U_UNDEFINED_KEYWORD, /**< Undefined Plural keyword */
U_DEFAULT_KEYWORD_MISSING, /**< Missing DEFAULT rule in plural rules */
U_DECIMAL_NUMBER_SYNTAX_ERROR, /**< Decimal number syntax error */
U_FMT_PARSE_ERROR_LIMIT, /**< The limit for format library errors */
/*
* the error code range 0x10200 0x102ff are reserved for Break Iterator related error
*/
U_BRK_INTERNAL_ERROR=0x10200, /**< An internal error (bug) was detected. */
U_BRK_ERROR_START=0x10200, /**< Start of codes indicating Break Iterator failures */
U_BRK_HEX_DIGITS_EXPECTED, /**< Hex digits expected as part of a escaped char in a rule. */
U_BRK_SEMICOLON_EXPECTED, /**< Missing ';' at the end of a RBBI rule. */
U_BRK_RULE_SYNTAX, /**< Syntax error in RBBI rule. */
U_BRK_UNCLOSED_SET, /**< UnicodeSet witing an RBBI rule missing a closing ']'. */
U_BRK_ASSIGN_ERROR, /**< Syntax error in RBBI rule assignment statement. */
U_BRK_VARIABLE_REDFINITION, /**< RBBI rule $Variable redefined. */
U_BRK_MISMATCHED_PAREN, /**< Mis-matched parentheses in an RBBI rule. */
U_BRK_NEW_LINE_IN_QUOTED_STRING, /**< Missing closing quote in an RBBI rule. */
U_BRK_UNDEFINED_VARIABLE, /**< Use of an undefined $Variable in an RBBI rule. */
U_BRK_INIT_ERROR, /**< Initialization failure. Probable missing ICU Data. */
U_BRK_RULE_EMPTY_SET, /**< Rule contains an empty Unicode Set. */
U_BRK_UNRECOGNIZED_OPTION, /**< !!option in RBBI rules not recognized. */
U_BRK_MALFORMED_RULE_TAG, /**< The {nnn} tag on a rule is mal formed */
U_BRK_ERROR_LIMIT, /**< This must always be the last value to indicate the limit for Break Iterator failures */
/*
* The error codes in the range 0x10300-0x103ff are reserved for regular expression related errrs
*/
U_REGEX_INTERNAL_ERROR=0x10300, /**< An internal error (bug) was detected. */
U_REGEX_ERROR_START=0x10300, /**< Start of codes indicating Regexp failures */
U_REGEX_RULE_SYNTAX, /**< Syntax error in regexp pattern. */
U_REGEX_INVALID_STATE, /**< RegexMatcher in invalid state for requested operation */
U_REGEX_BAD_ESCAPE_SEQUENCE, /**< Unrecognized backslash escape sequence in pattern */
U_REGEX_PROPERTY_SYNTAX, /**< Incorrect Unicode property */
U_REGEX_UNIMPLEMENTED, /**< Use of regexp feature that is not yet implemented. */
U_REGEX_MISMATCHED_PAREN, /**< Incorrectly nested parentheses in regexp pattern. */
U_REGEX_NUMBER_TOO_BIG, /**< Decimal number is too large. */
U_REGEX_BAD_INTERVAL, /**< Error in {min,max} interval */
U_REGEX_MAX_LT_MIN, /**< In {min,max}, max is less than min. */
U_REGEX_INVALID_BACK_REF, /**< Back-reference to a non-existent capture group. */
U_REGEX_INVALID_FLAG, /**< Invalid value for match mode flags. */
U_REGEX_LOOK_BEHIND_LIMIT, /**< Look-Behind pattern matches must have a bounded maximum length. */
U_REGEX_SET_CONTAINS_STRING, /**< Regexps cannot have UnicodeSets containing strings.*/
U_REGEX_OCTAL_TOO_BIG, /**< Octal character constants must be <= 0377. */
U_REGEX_MISSING_CLOSE_BRACKET, /**< Missing closing bracket on a bracket expression. */
U_REGEX_INVALID_RANGE, /**< In a character range [x-y], x is greater than y. */
U_REGEX_STACK_OVERFLOW, /**< Regular expression backtrack stack overflow. */
U_REGEX_TIME_OUT, /**< Maximum allowed match time exceeded */
U_REGEX_STOPPED_BY_CALLER, /**< Matching operation aborted by user callback fn. */
U_REGEX_ERROR_LIMIT, /**< This must always be the last value to indicate the limit for regexp errors */
/*
* The error code in the range 0x10400-0x104ff are reserved for IDNA related error codes
*/
U_IDNA_PROHIBITED_ERROR=0x10400,
U_IDNA_ERROR_START=0x10400,
U_IDNA_UNASSIGNED_ERROR,
U_IDNA_CHECK_BIDI_ERROR,
U_IDNA_STD3_ASCII_RULES_ERROR,
U_IDNA_ACE_PREFIX_ERROR,
U_IDNA_VERIFICATION_ERROR,
U_IDNA_LABEL_TOO_LONG_ERROR,
U_IDNA_ZERO_LENGTH_LABEL_ERROR,
U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR,
U_IDNA_ERROR_LIMIT,
/*
* Aliases for StringPrep
*/
U_STRINGPREP_PROHIBITED_ERROR = U_IDNA_PROHIBITED_ERROR,
U_STRINGPREP_UNASSIGNED_ERROR = U_IDNA_UNASSIGNED_ERROR,
U_STRINGPREP_CHECK_BIDI_ERROR = U_IDNA_CHECK_BIDI_ERROR,
/*
* The error code in the range 0x10500-0x105ff are reserved for Plugin related error codes
*/
U_PLUGIN_ERROR_START=0x10500, /**< Start of codes indicating plugin failures */
U_PLUGIN_TOO_HIGH=0x10500, /**< The plugin's level is too high to be loaded right now. */
U_PLUGIN_DIDNT_SET_LEVEL, /**< The plugin didn't call uplug_setPlugLevel in response to a QUERY */
U_PLUGIN_ERROR_LIMIT, /**< This must always be the last value to indicate the limit for plugin errors */
U_ERROR_LIMIT=U_PLUGIN_ERROR_LIMIT /**< This must always be the last value to indicate the limit for UErrorCode (last error code +1) */
} UErrorCode;
编码的识别
来自ByVoid 郭家宝
为什么用universalchardet?其实编码自动识别的解决方案不止一个,有icu提供的解决方案,IE也有API,还有已经在很多Linux发行版中的enca。之所以用universalchardet,是因为它是最合适的。IE的API不能跨平台,icu实现太庞大,enca是GPL(注意不是LGPL),使用它意味着我也要让我的所有源码使用GPL,而不是更加开放的Apache。universalchardet是MPL的,和LGPL差不多宽松,使用它是没有问题的。我非常不喜欢以GPL发布的函数库,这给开发者的限制太大了。
uchardet -universalchardet - Google Project Hosting
编译好的ucardet foxfire编码识别编译版
.