一 筹办常识
1,字符:字符是抽象的最小文本单位。它没有固定的外形(可能是一个字形),并且没有值。“A”是一个字符,“€”(德国、法国和很多其他欧洲国度通用货币的标记)也是一个字符。“中”“国”这是两个汉字字符。字符仅仅代表一个符号,没有任何实际值的意义。 2,字符集:字符集是字符的凑集。例如,汉字字符是中国人最先发明的字符,在中文、日文、韩文和越南文的书写中应用。这也说了然字符和字符集之间的关系,字符构成字符集(iso8859-1,GB2312/GBK,unicode)。 3,代码点:字符集中的每个字符都被分派到一个“代码点”。每个代码点都有一个特定的独一数值,称为标值。该标量值凡是用十六进制默示。 4,代码单位: 在每种编码情势中,代码点被映射到一个或多个代码单位。“代码单位”是各个编码体式格式中的单个单位。代码单位的大小等效于特定编码体式格式的位数: UTF-8 :UTF-8 中的代码单位由 8 位构成;在 UTF-8 中,因为代码单位较小的缘故,每个代码点经常被映射到多个代码单位。代码点将被映射到一个、两个、三个或四个代码单位; UTF-16 :UTF-16 中的代码单位由 16 位构成;UTF-16 的代码单位大小是 8 位代码单位的两倍。所以,标量值小于 U+10000 的代码点被编码到单个代码单位中; UTF-32:UTF-32 中的代码单位由 32 位构成; UTF-32 中应用的 32 位代码单位足够大,每个代码点都可编码为单个代码单位; GB18030:GB18030 中的代码单位由 8 位构成;在 GB18030 中,因为代码单位较小的缘故,每个代码点经常被映射到多个代码单位。代码点将被映射到一个、两个或四个代码单位。 5,举例:
“中国北京香蕉是个大笨伯”这是我定义的aka字符集;各字符对应代码点为: 北 00000001 京 00000010 香 10000001 蕉 10000010 是 10000100 个 10001000 大 10010000 笨 10100000 蛋 11000000 中 00000100 国 00001000 下面是我定义的 zixia 编码规划(8位),可以看到它的编码中默示了aka字符集的所有字符对应的 代码单位; 北 10000001 京 10000010 香 00000001 蕉 00000010 是 00000100 个 00001000 大 00010000 笨 00100000 蛋 01000000 中 10000100 国 10001000 所谓文本文件 就是我们按必然编码体式格式将二进制数据默示为对应的文本如 00000001000000100000010000001000000100000010000001000000如许的文件。我用一个支撑 zixia编码和aka字符集的记事本打开,它就遵守编码规划显示为 “香蕉是个大笨伯 ” 若是我把这些字符遵守GBK另存一个文件,那么则必然不是这个,而是 1100111111100011 1011110110110110 1100101011000111 1011100011110110 1011010011110011 1011000110111111 1011010110110000 110100001010
二,字符集
1, 常用字符集分类 ASCII及其扩大字符集 感化:表语英语及西欧说话。 位数:ASCII是用7位默示的,能默示128个字符;其扩大应用8位默示,默示256个字符。 局限:ASCII从00到7F,扩大从00到FF。 ISO-8859-1字符集 感化:扩大ASCII,默示西欧、希腊语等。 位数:8位, 局限:从00到FF,兼容ASCII字符集。 GB2312字符集 感化:国度简体中文字符集,兼容ASCII。 位数:应用2个字节默示,能默示7445个符号,包含6763个汉字,几乎覆盖所有高频率汉字。 局限:高字节从A1到F7, 低字节从A1到FE。将高字节和低字节分别加上0XA0即可获得编码。 BIG5字符集 感化:同一繁体字编码。 位数:应用2个字节默示,默示13053个汉字。 局限:高字节从A1到F9,低字节从40到7E,A1到FE。 GBK字符集 感化:它是GB2312的扩大,参加对繁体字的支撑,兼容GB2312。 位数:应用2个字节默示,可默示21886个字符。 局限:高字节从81到FE,低字节从40到FE。 GB18030字符集 感化:它解决了中文、日文、朝鲜语等的编码,兼容GBK。 位数:它采取变字节默示(1 ASCII,2,4字节)。可默示27484个文字。 局限:1字节从00到7F; 2字节高字节从81到FE,低字节从40到7E和80到FE;4字节第一三字节从81到FE,第二四字节从30到39。 UCS字符集 感化:国际标准 ISO 10646 定义了通用字符集 (Universal Character Set)。它是与UNICODE同类的组织,UCS-2和UNICODE兼容。 位数:它有UCS-2和UCS-4两种格局,分别是2字节和4字节。 局限:今朝,UCS-4只是在UCS-2前面加了0×0000。 UNICODE字符集 感化:为世界650种说话进行同一编码,兼容ISO-8859-1。 位数:UNICODE字符集有多个编码体式格式,分别是UTF-8,UTF-16和UTF-32。 2 ,按所默示的文字分类 说话 字符集 正式名称 英语、西欧语 ASCII,ISO-8859-1 MBCS 多字节 简体中文 GB2312 MBCS 多字节 繁体中文 BIG5 MBCS 多字节 简繁中文 GBK MBCS 多字节 中文、日文及朝鲜语 GB18030 MBCS 多字节 各国说话 UNICODE,UCS DBCS 宽字节
三,编码
UTF-8:采取变长字节 (1 ASCII, 2 希腊字母, 3 汉字, 4 平面符号) 默示,收集传输, 即使错了一个字节,不影响其他字节,而双字节只要一个错了,其他也错了,具体如下: 若是只有一个字节则其最高二进制位为0;若是是多字节,其第一个字节从最高位开端,连气儿的二进制位值为1的个数决意了其编码的字节数,其余各字节均以10开首。UTF-8最多可用到6个字节。
UTF-16:采取2字节,Unicode中不合项目组的字符都同样基于现有的标准。这是为了便于转换。从 0×0000到0×007F是ASCII字符,从0×0080到0×00FF是ISO-8859-1对ASCII的扩大。希腊字母表应用从0×0370到 0×03FF 的代码,斯拉夫语应用从0×0400到0×04FF的代码,美国应用从0×0530到0×058F的代码,希伯来语应用从0×0590到0×05FF的代 码。中国、日本和韩国的象形文字(总称为CJK)占用了从0×3000到0×9FFF的代码;因为0×00在c说话及操纵体系文件名等中有特别意义,故很 多景象下须要UTF-8编码保存文本,去掉这个0×00。举例如下: UTF-16: 0×0080 = 0000 0000 1000 0000 UTF-8: 0 xC280 = 1100 0010 1000 0000 UTF-32:采取4字节。 优毛病 UTF-8、UTF-16和UTF-32都可以默示有效编码空间 (U+000000-U+10FFFF) 内的所有Unicode字符。 应用UTF-8编码时ASCII字符只占1个字节,存储效力斗劲高,实用于拉丁字符较多的场合以节俭空间。 对于大多半非拉丁字符(如中文和日文)来说,UTF-16所需存储空间最小,每个字符只占2个字节。 Windows NT内核是Unicode(UTF-16),采取UTF-16编码在调用体系API时无需转换,处理惩罚速度也斗劲快。 采取UTF-16和UTF-32会有Big Endian和Little Endian之分,而UTF-8则没有字节次序题目,所以UTF-8合适传输和通信。 UTF-32采取4字节编码,一方面处理惩罚速度斗劲快,但另一方面也浪费了多量空间,影响传输速度,因而很少应用。
四,如何断定字符集
1,字节序 起首说一下字节序对编码的影响,字节序分为Big Endian字节序和Little Endian字节序。不合的处理惩罚器可能不一样。所以,传输时须要告诉处理惩罚器当时的编码字节序。对于前者而言,高位字节存在低地址,低字节存于高地址;后者相反。例如,0X03AB, Big Endian字节序 0000: 0 3 0001: AB Little Endian字节序是 0000: AB 0001: 0 3 2,编码辨认 UNICODE,按照前几个字节可以断定UNICODE字符集的各类编码,叫做Byte Order Mask办法BOM: UTF-8: EFBBBF (合适UTF-8格局,请看上方。但没有含义在UCS即UNICODE中) UTF-16 Big Endian:FEFF (没有含义在UCS-2中) UTF-16 Little Endian:FFFE (没有含义在UCS-2中) UTF-32 Big Endian:0000FEFF (没有含义在UCS-4中) UTF-32 Little Endian:FFFE0000 (没有含义在UCS-4中)
GB2312:高字节和低字节的第1位都是1。
BIG5,GBK&GB18030:高字节的第1位为1。操纵体系有默认的编码,常为GBK,可以下载此外并进级。经由过程断定高字节的第1位从而知道是ASCII或者汉字编码。
摘自: http://blog.minidx.com/2008/12/06/1689.html
字符编码笔记:ASCII,Unicode和UTF-8
摘自:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
今天正午,我忽然想搞清楚Unicode和UTF-8之间的关系,于是就开端在网上查材料。
成果,这个题目比我想象的错杂,从午饭后一向看到晚上9点,才算初步搞清楚。
下面就是我的笔记,首要用来收拾本身的思路。然则,我尽量试图写得通俗易懂,欲望能对其他伴侣有效。毕竟成果,字符编码是策画机技巧的基石,想要谙练应用策画机,就必须懂得一点字符编码的常识。
1. ASCII码
我们知道,在策画机内部,所有的信息终极都默示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状况,是以八个二进制位就可以组合出256种状况,这被称为一个字节(byte)。也就是说,一个字节一共可以用来默示256种不合的状况,每一个状况对应一个符号,就是256个符号,从0000000到11111111。
上个世纪60年代,美国制订了一套字符编码,对英语字符与二进制位之间的关系,做了同一规定。这被称为ASCII码,一向沿用至今。
ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包含32个不克不及打印出来的把握符号),只占用了一个字节的后面7位,最前面的1位同一规定为0。
2、非ASCII编码
英语用128个符号编码就够了,然则用来默示其他说话,128个符号是不敷的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码默示。于是,一些欧洲国度就决意,哄骗字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。如许一来,这些欧洲国度应用的编码体系,可以默示最多256个符号。
然则,这里又呈现了新的题目。不合的国度有不合的字母,是以,哪怕它们都应用256个符号的编码体式格式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (?),在俄语编码中又会代表另一个符号。然则不管如何,所有这些编码体式格式中,0—127默示的符号是一样的,不一样的只是128—255的这一段。
至于亚洲国度的文字,应用的符号就更多了,汉字就多达10万阁下。一个字节只能默示256种符号,必然是不敷的,就必须应用多个字节表达一个符号。比如,简体中文常见的编码体式格式是GB2312,应用两个字节默示一个汉字,所以理论上最多可以默示256x256=65536个符号。
中文编码的题目须要专文评论辩论,这篇笔记不涉及。这里只指出,固然都是用多个字节默示一个符号,然则GB类的汉字编码与后文的Unicode和UTF-8是毫无关系的。
3.Unicode
正如上一节所说,世界上存在着多种编码体式格式,同一个二进制数字可以被申明成不合的符号。是以,要想打开一个文本文件,就必须知道它的编码体式格式,不然用错误的编码体式格式解读,就会呈现乱码。为什么电子邮件经常呈现乱码?就是因为发信人和收信人应用的编码体式格式不一样。
可以想象,若是有一种编码,将世界上所有的符号都纳入此中。每一个符号都赐与一个独一无二的编码,那么乱码题目就会消散。这就是Unicode,就像它的名字都默示的,这是一种所有符号的编码。
Unicode当然是一个很大的凑集,如今的范围可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639默示阿拉伯字母Ain,U+0041默示英语的大写字母A,U+4E25默示汉字“严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。
4. Unicode的题目
须要重视的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应当如何存储。
比如,汉字“严”的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的默示至少须要2个字节。默示其他更大的符号,可能须要3个字节或者4个字节,甚至更多。
这里就有两个严重的题目,第一个题目是,如何才干差别unicode和ascii?策画机怎么知道三个字节默示一个符号,而不是分别默示三个符号呢?第二个题目是,我们已经知道,英文字母只用一个字节默示就够了,若是unicode同一规定,每个符号用三个或四个字节默示,那么每个英文字母前都必定有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会是以大出二三倍,这是无法接管的。
它们造成的成果是:1)呈现了unicode的多种存储体式格式,也就是说有很多种不合的二进制格局,可以用来默示unicode。2)unicode在很长一段时候内无法推广,直到互联网的呈现。
5.UTF-8
互联网的普及,强烈请求呈现一种同一的编码体式格式。UTF-8就是在互联网上应用最广的一种unicode的实现体式格式。其他实现体式格式还包含UTF-16和UTF-32,不过在互联网上根蒂根基不消。反复一遍,这里的关系是,UTF-8是Unicode的实现体式格式之一。
UTF-8最大的一个特点,就是它是一种变长的编码体式格式。它可以应用1~4个字节默示一个符号,按照不合的符号而变更字节长度。
UTF-8的编码规矩很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。是以对于英语字母,UTF-8编码和ASCII码是雷同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有说起的二进制位,全部为这个符号的unicode码。
下表总结了编码规矩,字母x默示可用编码的位。
Unicode符号局限 | UTF-8编码体式格式 (十六进制) | (二进制) --------------------+--------------------------------------------- 0000 0000-0000 007F | 0 xxxxxxx 0000 0080-0000 07FF | 110 xxxxx 10 xxxxxx 0000 0800-0000 FFFF | 1110 xxxx 10 xxxxxx 10 xxxxxx 0001 0000-0010 FFFF | 11110 xxx 10 xxxxxx 10 xxxxxx 10 xxxxxx
下面,还是以汉字“严”为例,演示如何实现UTF-8编码。
已知“严”的unicode是4E25(100111000100101),按照上表,可以发明4E25处在第三行的局限内(0000 0800-0000 FFFF),是以“严”的UTF-8编码须要三个字节,即格局是“1110 xxxx 10 xxxxxx 10 xxxxxx”。然后,从“严”的最后一个二进制位开端,依次从后向前填入格局中的x,多出的位补0。如许就获得了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。
6. Unicode与UTF-8之间的转换
经由过程上一节的例子,可以看到“严”的Unicode码是4E25,UTF-8编码是E4B8A5,两者是不一样的。它们之间的转换可以经由过程法度实现。
在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编码,也就是上一节谈到的编码办法。
选择完”编码体式格式“后,点击”保存“按钮,文件的编码体式格式就立即转换好了。
7. Little endian和Big endian
上一节已经提到,Unicode码可以采取UCS-2格局直接存储。以汉字”严“为例,Unicode码是4E25,须要用两个字节存储,一个字节是4E,另一个字节是25。存储的时辰,4E在前,25在后,就是Big endian体式格式;25在前,4E在后,就是Little endian体式格式。
这两个古怪的名称来自英国作家斯威夫特的《格列佛纪行》。在该书中,小人国里爆发了内战,战斗原由是人们争辩,吃鸡蛋时毕竟是从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。为了这件工作,前后爆发了六次战斗,一个皇帝送了命,另一个皇帝丢了王位。
是以,第一个字节在前,就是”大头体式格式“(Big endian),第二个字节在前就是”小头体式格式“(Little endian)。
那么很天然的,就会呈现一个题目:策画机怎么知道某一个文件到底采取哪一种体式格式编码?
Unicode规范中定义,每一个文件的最前面分别参加一个默示编码次序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF默示。这正好是两个字节,并且FF比FE大1。
若是一个文本文件的头两个字节是FE FF,就默示该文件采取大头体式格式;若是头两个字节是FF FE,就默示该文件采取小头体式格式。
8. 实例
下面,举一个实例。
打开”记事本“法度Notepad.exe,新建一个文本文件,内容就是一个”严“字,依次采取ANSI,Unicode,Unicode big endian 和 UTF-8编码体式格式保存。
然后,用文本编辑软件UltraEdit中的”十六进制功能“,调查该文件的内部编码体式格式。
1)ANSI:文件的编码就是两个字节“D1 CF”,这恰是“严”的GB2312编码,这也暗示GB2312是采取大头体式格式存储的。
2)Unicode:编码是四个字节“FF FE 25 4E”,此中“FF FE”注解是小头体式格式存储,真正的编码是4E25。
3)Unicode big endian:编码是四个字节“FE FF 4E 25”,此中“FE FF”注解是大头体式格式存储。
4)UTF-8:编码是六个字节“EF BB BF E4 B8 A5”,前三个字节“EF BB BF”默示这是UTF-8编码,后三个“E4B8A5”就是“严”的具体编码,它的存储次序与编码次序是一致的。
9. 延长浏览
* The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets(关于字符集的最根蒂根基常识)
* 谈谈Unicode编码
* RFC3629:UTF-8, a transformation format of ISO 10646(若是实现UTF-8的规定)
(完)
C++的中英文字符串默示(string,wstring)
(畴前面的材料可知,string完全可以存储中文(有效编码只有""\0""=0,其他字符均不为0),然则在显示、字符操纵等方面是无法包管的!)
在C++中字符串类的string的模板原型是basic_string
template <class _Elem, class traits = char_traits<_Elem>, class _Ax = allocator<_Elem>> class basic_string{};
第一个参数_Elem默示类型。第二个参数traits的缺省值应用char_traits类型,定义了类型和字符操纵的函数,如斗劲、等价、分派等。第三个参数_Ax的默认值是allocator类,默示了内存模式,不合的内存布局将操纵指针的不合行动,例如栈、堆或段内存模式等。
在C++标准里定义了两个字符串string和wstring
typedef basic_string<char> string; typedef basic_string<wchar_t> wstring;
前者string是常用类型,可以看作char[],其实这恰是与string定义中的_Elem=char相一致。而wstring,应用的是wchar_t类型,这是宽字符,用于满足非ASCII字符的请求,例如Unicode编码,中文,日文,韩文什么的。对于wchar_t类型,实际上C++中都用与char函数相对应的wchar_t的函数,因为他们都是从同一个模板类似于上方的体式格式定义的。是以也有wcout, wcin, werr等函数。
实际上string也可以应用中文,然则它将一个汉字写在2个char中。而若是将一个汉字看作一个单位wchar_t的话,那么在wstring中就只占用一个单位,其它的非英文文字和编码也是如此。如许才真正的满足字符串操纵的请求,尤其是国际化等工作。
看一下下面的法度,就会懂得两者的差别。
#include <iostream> #include <string> using namespace std; #define tab "\t" int main() { locale def; cout<<def.name()<<endl; locale current = cout.getloc(); cout<<current.name()<<endl; float val=1234.56; cout<<val<<endl; //chage to french/france cout.imbue(locale("chs")); current=cout.getloc(); cout<<current.name()<<endl; cout<<val<<endl; //上方是申明locale的用法,下面才是本例的内容,因为此顶用到了imbue函数 cout<<"*********************************"<<endl; //为了包管本地化输出(文字/时候/货币等),chs默示中国,wcout必须应用本地化解析编码 wcout.imbue(std::locale("chs")); //string 英文,正确倒置地位,显示第二个字符正确 string str1("ABCabc"); string str11(str1.rbegin(),str1.rend()); cout<<"UK\ts1\t:"<<str1<<tab<<str1[1]<<tab<<str11<<endl; //wstring 英文,正确倒置地位,显示第二个字符正确 wstring str2=L"ABCabc"; wstring str22(str2.rbegin(),str2.rend()); wcout<<"UK\tws4\t:"<<str2<<tab<<str2[1]<<tab<<str22<<endl; //string 中文,倒置后,变成乱码,第二个字符读取也错误 string str3("你好么?"); string str33(str3.rbegin(),str3.rend()); cout<<"CHN\ts3\t:"<<str3<<tab<<str3[1]<<tab<<str33<<endl; //正确的打印第二个字符的办法 cout<<"CHN\ts3\t:RIGHT\t"<<str3[2]<<str3[3]<<endl; //中文,正确倒置地位,显示第二个字符正确 wstring str4=L"你好么?"; wstring str44(str4.rbegin(),str4.rend()); wcout<<"CHN\tws4\t:"<<str4<<tab<<str4[1]<<tab<<str44<<endl; wstring str5(str1.begin(),str1.end());//只有char类型的string时才可以如此机关 wstring str55(str5.rbegin(),str5.rend()); wcout<<"CHN\tws5\t:"<<str5<<tab<<str5[1]<<tab<<str55<<endl; wstring str6(str3.begin(),str3.end());//如此机关将失败!!!! wstring str66(str6.rbegin(),str6.rend()); wcout<<"CHN\tws6\t:"<<str6<<tab<<str6[1]<<tab<<str66<<endl; return 0; }
成果如下:(略)
上方显示了本地化的感化,是在数字中每三位加一个逗号,其实对时候/文字等都是用影响的。
下面的输出说了然,如何正确应用string和wstring的办法。第三个因为应用string来默示汉字,呈现了一些错误。最后一行也是错误,导致了输出也受到了影响,没有空格与回车。(最后两个就不要管中英文了,仅仅申明一下中文机关办法是错误的)
《把握标准C++类》在第十二章《说话支撑》中专门讲C++的国际化和本地化题目,C++供给了I18N的标准处理惩罚,软件开辟者可以参考。
C++标准库还是很是博大高深的,功能斗劲齐备的。持续进修。
摘自: http://www.cnblogs.com/xiaoyz/archive/2008/10/11/1308860.html
作者:zhenjing.chen
出处:http://www.cnblogs.com/zhenjing/
未注明转载的文章,版权归作者所有,迎接转载,但未经作者赞成必须保存此段声明,且在文章页面明显地位给出原文连接,不然保存究查法令义务的权力。