- 浏览: 28178 次
- 性别:
- 来自: 杭州
-
最新评论
转自 http://blog.csdn.net/gqqnb/article/details/6266542
我决心了解一下编码知识——主要是Unicode——及相关概念,搜索阅读了网上的很多文章,明白了一些,另一些却很模糊,而且有一些不同文章的描述是冲突的!我因此查阅了很多网上的资料,主要有中英文维基百科和Unicode.org,终于明白了其中的奥妙。
独乐乐不如众乐乐,我因此撰此文帮助大家最大程度地厘清Unicode、UCS、UTF-8、UTF-16、UCS-2、UCS-4之间的关系。对于网上随手可得的资料,如ASCII码表、UTF-16算法的程序代码,则不是本文重点。
网上其他文章概念模糊、说法冲突,我觉得一是上述词语本身就具有多重含义,很难把握;二可能是作者本身理解不到位,含糊了过去;三可能是那些文章缺少精确的表达方式,很容易使人误解。于是,我选择了用数学及程序代码相结合的方式,试图给予最清晰的定义。
我水平亦有限,哪里理解不到位或表达不清楚,希望读者不吝赐教。
这里格式我不修改了,嫌格式不漂亮的朋友可去https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0B92-FAjNvVzGNGQxNGI2MzctZGJlMC00YzhmLTg3MWItMGI0MWVhOTM4M2I4&hl=zh_CN 获取PDF版。
基本概念
字符是文字与符号的总称,包括文字、图形符号、数学符号等。字符集是字符的集合。
(字符)编码当名词用,是一个从一指定字符集到一指定集合的函数,如果用程序代码1来表示,可以写作Encoding。
编码当动词用,是建立一个从一指定字符集到一指定集合的函数。例如将汉字对应到整数(Encoding),将英文字母对应到可在电线中传输的电脉冲(Encoding电脉冲模式>)。
如果字符编码特化为Encoding,即字符转换为整数,则成为编码字符集(函数是特殊的集合)。很多文章上说的字符集其实是编码字符集。
码点是编码字符集的上域2中的一个元素。
为了本文的叙述方便,额外定义几条表达方式。
编码字符集有以下属性:
编码字符集ASCII中字符A的编码数字是65。6 4
编码字符集ASCII中字符A的二进制流是01000001。相应地,十六进制流是41,十进制流是65。与编码数字不同,N进制流要开头补0,以达到表示长度。 5
常见的编码字符集
GB2312是简体字集,全称为GB2312(80)字集,共包括国标简体汉字6763个。
BIG5大五码是台湾繁体字集,共包括国标繁体汉字13053个。
GBK是简繁字集,包括了GB字集、BIG5字集和一些符号,共包括21003个字符。
GB18030是国家制定的一个强制性大字集标准,全称为GB18030-2000,它的推出使汉字集有了一个“大一统”的标准。
ASCII
我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位有0和1两种状态,因此八个二进制位就可以组合出 256种状态,这被称为一个字节。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000到11111111。
上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。
ASCII的字库包括128个字符,比如空格(SPACE)的编码数字是32,二进制流是00100000。这128个字符(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。
在电线里传输被ASCII编码的二进制流时,为了检验错误,会修改最高位,用来做奇偶校验。这利用了ASCII本身的性质(最高位都是0)。
UCS
ISO10646标准所定义的通用字符集(Universal Character Set),编码长度可达32位。
Unicode
Unicode是一种正在发展的编码字符集,由统一码联盟制定,希望将全世界常用文字都函括进去。Unicode兼容ASCII。7即ASCII中有的字符Unicode中都有,并且对应相同的编码数字。
Unicode编码长度可达到32位,即4字节。第一字节称为组,第二字节称为面,第三字节称为行,第四字节称为点。第0组第0面里的字符可以只用2个字节表示,且涵盖了绝大部分的常用字,所以备受青睐。为了方便称呼,Unicode给它了一个名称——基本多文种平面(BMP)。基本多文种平面值域和上域都是0到FFFF,共计65535个码点。8 9基本多文种平面是Unicode的子集。
虽然Unicode的表示长度是32位,但因为通常表示的是常用字,且常用字在BMP的字库里,所以表示长度往往缩减为16位。
Unicode与UCS的关系
ISO与统一码联盟是两个不同的组织,最初制定了不同的标准;但后来两个组织制定的编码字符集相互兼容。10现在往往只说Unicode,UCS这个名词不常见。
转换格式
以上说的都只是编码字符集——字符到整数的函数。虽然表示长度往往是8的倍数,却没有规定二进制流应该如何放入到几个字节里去。
比如,Unicode中字符“严”的十六进制流是4E25(缩减了的表示长度),是直接保存为两个字节4E和25呢,还是经过一些运算再保存呢?
读者可能觉得这个问题很无聊。我们已经知道,英文字母只用一个字节表示就够了,如果每个符号用两个或四个字节表示,那么每个英文字母前都必然有二到四个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。
UTF正是为了解决这个问题而诞生的。UTF全称为Unicode Translation Format(Unicode转换格式)。
转换格式是一个从二进制流集合到字节数组的集合的函数,可以写作Encoding。又二进制流可以计算为数字,转换格式可以写作Encoding。
UTF-8
UTF-8是一种变长转换格式。它使用1~4个字节表示一个符号,根据不同的二进制流而改变字节长度。
UTF-8的规则很简单,只有二条:
-
对于单字节的符号,字节的第一位设为0,后面7位为这个符号的Unicode码。因此对于同一个英语字母在UTF-8下和在ASCII码下的像11是相同的。
-
对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的二进制位用来从后往前放置这个符号的二进制流。
下表总结了编码规则,字母x表示用来放置二进制码的位置。
Unicode码点 |
像(二进制) |
0000 0000 - 0000 007F |
0xxxxxxx |
0000 0080 - 0000 07FF |
110xxxxx 10xxxxxx |
0000 0800 - 0000 FFFF |
1110xxxx 10xxxxxx 10xxxxxx |
0001 0000 - 0010 FFFF |
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
UTF-16
UTF-16的编码方法12是:
-
如果二进制流b小于0x10000,也就是十进制的0到65535之内,则直接使用两字节表示。
-
如果二进制流b大于等于0x10000,将b-0x10000的结果中的前 10 位作为高位和0xD800进行逻辑或操作,将后10 bit作为低位和0xDC00做逻辑或操作,这样组成的4个字节就构成了b的编码。
举个例子。假设要算(U+2A6A5,四个繁体字龙)13在UTF-16下的像,因为它超过 U+FFFF,所以 2A6A5-10000=0x1A6A5=。
前10位0001 1010 01 | 0xD800 = 0xD896。
后10位10 1010 0101 | 0xDC00 = 0xDEA5。
所以U+ 2A6A5 在UTF-16中的像是D8 96 DE A5。
UCS-2
UCS-2是ISO制定的,用来转换UCS的。但既然Unicode和UCS相互兼容,便也可以用来转换Unicode。
UCS-2是基本多文种平面的值域到两个成员的字节数组的集合的函数,即每个BMP码点都通过前面补0的方式固定地用两个字节表示。记得因为代理区的存在,一个码点并不代表一个字符。
UCS-2是UTF-16的子集,因为UTF-16额外规定了BMP以外的字节表示。
UCS-4
UCS-4是ISO制定的,用来转换UCS的。但既然Unicode和UCS相互兼容,便也可以用来转换Unicode。
UCS-4是Unicode中的头128组的值域到四个成员的字节数组的集合的函数,即每个码点都通过前面补0的方式固定地用四个字节表示。四个字节的范围是0到7FFFFFFF,即31个二进制位。
UTF-32
但是,ISO/IEC 10646已经宣布,今后所有的字符都将分配在10FFFF (即第0组头17个平面)以内,所以UCS-4的7FFFFFFF上限没有意义。14所以制定了UTF-32。
UTF-32是Unicode中第0组头17个平面的值域到四个成员的字节数组的集合的函数,即每个Unicode码点都通过前面补0的方式固定地用四个字节表示。
可见,UTF-32是UCS-4的子集,UCS-4包含UTF-32。15UCS-4已经没有使用的意义。
小结
转换格式 |
定义域 |
值域 |
UTF-8 |
0-10 FFFF 第0组头17平面的值域 |
1-4字节 |
UTF-16 |
0-10FFFF 第0组头17平面的值域 |
2或4字节 |
UCS-2 |
0-FFFF 基本多文种平面的值域 |
2字节 |
UCS-4 |
0-7FFFFFFF 头128组的值域 |
4字节 |
UTF-32 |
0-10 FFFF 第0组头17平面的值域 |
4字节 |
* 缩进代表包含关系。
现在若有软件声称自己支持UCS-2,那其实是暗指它不能支持在UTF-16中超过2字节的符号。16
字节存储的顺序
一个字符,通过Unicode,得到了二进制流;二进制流通过转换格式,得到了几个字节。那么这几个字节是由低位到高位(即低位在前)写入硬盘呢,还是由高位到低位(即高位在前)写入硬盘呢?这就是字节存储的顺序问题,即字节序问题。
为什么不统一地都由低位到高位或由高位到低位呢?因为设备执行不同的任务时,这两种方式的性能有差别。为了最大地提升性能,设备的硬件实现根据其最常做的任务决定了字节序。
Unicode规范中用字节序标记字符(BOM)来标识字节序,它的编码是FEFF。这样如果接收者收到FEFF,就表明这个字节流是高位在前的;如果收到FFFE,就表明这个字节流是低位在前的。
这里相当于有一个从byte[]和BOM到byte[]的字节序函数(b(byte[],bom):byte[]),给定几个字节和字节序,该函数就能算出这几个字节存往硬盘的顺序。
至此,计算机屏幕上显示的字符保存到硬盘上的过程已经清晰了:
对该字符c应用编码字符集,结果为n。 |
Encoding(c) → n |
对整数n应用转换格式,结果为。 |
Encoding(n) → bytes |
对应用字节序函数,结果为硬盘上的字节数组。 |
b(bytes,bom) → bytesInDisk |
UTF-8有严格的字节顺序,不需要BOM。但如果在字节流前面加上BOM在UTF-8下的像EF BB BF,接收者一收到就知道这是UTF-8编码。所以用UTF-8格式存储,仍然会往文件头写EF BB BF,以表明其转换方法。
UTF-16、UCS-2、UCS-4、UTF-32都没有严格的顺序,所以需要借助BOM。
复合函数
数学上的复合函数是一个函数。若g(x)、f(x)是函数,则g(f(x))是复合函数。
编码字符集ASCII因为不需要转换格式17、没有字节序的问题,所以ASCII又是:
-
编码字符集ASCII与转换格式的复合函数(转换格式不作任何事)
-
编码字符集ASCII、转换格式与字节序函数的复合函数(转换格式和字节序函数不作任何事)
UTF-8第一条规则用的就是上面的第一个含义。
UTF-16BE和UTF-16LE,是转换格式UTF-16与高位在前或低位在前的复合。UTF-16BE有时缩写为UTF-16,注意,这与转换格式UTF-16是不同的!18
UCS-2BE和UCS-2LE,是转换格式UCS-2与高位在前或低位在前的复合。UCS-2BE有时缩写为UCS-2。注意,这与转换格式UCS-2是不同的!3
UCS-4BE和UCS-4LE,是转换格式UCS-4与高位在前或低位在前的复合。UCS-4BE有时缩写为UCS-4。注意,这与转换格式UCS-4是不同的!3
UTF-32BE和UTF-32LE,是转换格式UTF-32与高位在前或低位在前的复合。UTF-32BE有时缩写为UTF-32。注意,这与转换格式UTF-32是不同的!19
名称 |
编码次序 |
字节存储顺序 |
||||
BOM |
朱 |
, |
聿 |
|
||
UTF-16LE |
低位在前 |
无 |
31 67 |
2C 00 |
7F 80 |
69 D8 A5 DE |
UTF-16BE |
高位在前 |
无 |
67 31 |
00 2C |
80 7F |
D8 69 DE A5 |
UTF-16 |
低位在前,包含BOM |
FF FE |
31 67 |
2C 00 |
7F 80 |
69 D8 A5 DE |
UTF-16 |
高位在前,包含BOM |
FE FF |
67 31 |
00 2C |
80 7F |
D8 69 DE A5 |
Windows记事本中的编码
我们在Windows系统中保存文本文件时通常可以选择编码为ANSI、Unicode、Unicode big endian和UTF-8。已知Unicode是编码字符集,big endian是一种字节序,UTF-8是转换格式。这三种不同的东西放在一起,是什么意思呢?答案是复合函数。
请看实验!我将字符用这四种选项分别保存,然后查看其16进制代码。记得这个字的二进制流是2A6A5,在UTF-16中的像是D8 96 DE A5。读者可以练习一下计算2A6A5在UTF-8下的像。
选项 |
编码字符集 |
转换格式 |
字节存储的顺序 |
ANSI |
英文文件:ASCII |
直接表示 |
直接存储 |
简体中文系统:GB2312 |
|
|
|
繁体中文系统:Big5 |
|
|
|
Unicode |
Unicode |
UTF-16 |
低位在前 |
Unicode big endian |
Unicode |
UTF-16 |
高位在前 |
UTF-8 |
Unicode |
UTF-8 |
直接存储 |
所以,以上四项都是复合函数,复合了编码字符集、二进制的字节表示和字节存储的顺序。
很多软件和文章中提到的Unicode、UTF-8之类的,都是这种复合。
爱让一切都对了
2011年3月213月21日 月21日 星期21日 星期一日 星期一
本文依照知识共享- 署名-相同方式共享3.0协议发表

四个繁体字龙
1C#语法,依据.Net Framework 4.0
2编码字符集是函数,函数有值域。值域是上域的子集。Unicode中有些位置是保留区域,没有字符来对应,所以不属于值域,但属于上域。
3即函数的定义域。
4即值域的基数的二进制表示的位数。
5即上域的基数的二进制表示的位数。
6即字符A在编码字符集ASCII中的像是01000001。
8基本多文种平面里有个代理区,仅该区就可表达1048576个字符。
11将UTF-16看成函数。设有函数f,则x在f下的是f(x)。若f(x)=2x+1,则3在f下的像是。
13文末有该字的图片。
14http://en.wikipedia.org/wiki/Universal_Character_Set#Encoding_forms_of_the_Universal_Character_Set。但正在请求来源。
17作动词用。不同于上文的名词转换格式。
18根据Vim FencView插件。
19这是我的推理。
发表评论
-
深入了解字符集和编码
2012-03-09 17:21 933一、什么是字符集?什么是编码? 字符(Characte ... -
[转]字符编码详解及由来(UNICODE,UTF-8,GBK)
2012-03-08 17:55 733from http://blog.csdn.net/st ... -
velocity 笔记
2012-02-24 13:54 932Single quotes will ensure that ... -
[转]java InputStream读取数据问题
2012-01-30 11:25 926http://www.cnblogs.com/MyFa ... -
windows 文件名 正则表达式
2011-09-30 17:14 2272一个简单的windows 文件名 正则表达式,不检查文件名如 ... -
[转]HD9001: 各浏览器对 URI 中非 ASCII 字符的处理有差异
2011-08-25 15:56 1095作者:孙东国 标准参考 URI 的组成如下所示: ... -
【原创】各种编码的关系
2011-07-02 15:54 1027以下为个人总结,有问题欢迎指出。 ASCII 8位 I ... -
【转】Facebook 的系统架构
2011-06-13 14:27 966来源:http://www.quora.co ... -
[转]java并发编程实践笔记
2011-04-07 17:27 7871, 保证线程安全的三种方法 :a, 不要跨线程访问共享变 ... -
[原创]AutoResetEvent, ManualResetEvent的Java模拟
2011-04-07 16:39 3042AutoResetEvent, ManualResetE ... -
[转]java 线程小结
2011-04-07 16:23 10211, 为什么wait与notify之前必须要加synchr ... -
[转]Java集合的五点体会
2011-04-06 10:17 688The Collections classes in j ...
相关推荐
4. **学术研究**:在进行语言学或文化研究时,Unicode汉字内码表可以帮助研究人员更精确地引用和分析文本。 ### 结论 总之,Unicode汉字内码表是中文信息化不可或缺的一部分,它不仅为计算机系统提供了处理汉字的...
这对于编程或文本处理时需要精确操作字符编码的场景尤其有用。 3. **编码/解码**:工具能将文本转换成Unicode编码形式(如UTF-8、UTF-16等)和从Unicode编码恢复原始文本,这对于跨平台数据传输和存储至关重要。 4...
为了解决上述问题,我们可以编写自定义的VB函数来实现更精确的UTF-8到Unicode的转换。以下是一个具体的实现示例: ```vb Private Function Utf8ToUnicode(ByRef Utf() As Byte) As String Dim UtfLen As Long ...
2. **自然语言处理**:在NLP领域,例如中文分词、情感分析等任务中,需要对汉字进行精确识别和处理,Unicode编码提供了统一的编码标准,而拼音则有助于理解和分析汉字的语义和发音特征。 3. **教育领域**:在学习...
点阵字库通常用于控制字符的精确显示,尤其在有限的屏幕空间或打印质量不高的设备上。 4. uni2gbk.bin: 这个文件名暗示了一个从Unicode到GBK的转换工具或者数据文件。在处理中文文本时,如果需要在不支持Unicode的...
如果需要更精确的控制转换过程,可以编写自定义的解析函数。例如,遍历字符串,手动转换每个字符到整数: ```cpp CString str = L"1234"; int num = 0; for (int i = 0; i (); i++) { num = num * 10 + (str[i...
Unicode字符编码表是计算机科学领域中的一个重要概念,它不仅代表着一种技术标准,更是全球信息交流统一化的...随着技术的不断进步,Unicode的角色会越来越重要,它将推动全球化的进程,让信息共享变得更加便捷和精确。
5. **正则表达式处理**:在处理包含特殊字符的正则表达式时,了解Unicode编码可以帮助编写更精确的匹配规则。 需要注意的是,这个Unicode工具依赖于SWT(Standard Widget Toolkit),这是一个开源的GUI库,主要用于...
- **RORM/MEDIAL/F/0/R/M:** 这部分可能是对字符形式的分类,但具体内容未给出,难以精确解读。 - **INITIAL FORM/ISOLATED FORM:** 这两列分别表示字母在词首位置(初始形态)和孤立状态下(不与其他字母相连时)...
【VC++下的Unicode编程】 在计算机领域,Unicode是一种...总之,Unicode编程在VC++中对于开发支持多语言的应用程序至关重要,它克服了ASCII编码的局限性,并通过宽字符和相关的库函数,使得字符串处理更加高效和精确。
生成编码文件的控制台程序。 运行后,编码保存在"D:\unicode.txt" 【精确度低-许多外国字都不能显示】 网速不给力,且只需要中文和英文部分的可以用这个。 汉字主要部分是从4E00开始的。
这种方式的好处在于可以精确控制每个字符的转换结果,尤其是对于那些不在标准GSM7Bit字符集中的特殊字符。 ### 总结 从GSM7Bit到Unicode的转换对于处理跨平台、跨系统的文本数据非常重要。通过上述代码示例,我们...
了解这些编码对于开发人员来说至关重要,特别是在编写需要捕捉键盘事件的应用程序时,它可以帮助他们更精确地识别用户的输入意图,并据此执行相应的操作。通过深入掌握键盘按键的Unicode编码,开发人员可以提升用户...
需要注意的是,虽然UTF-8已经成为互联网上最广泛使用的编码,但Unicode也有其优势,特别是在处理需要精确字节对齐的场合。因此,理解和掌握这两种编码方式及其转换工具对于IT专业人员来说是至关重要的技能。
而在另外一个编码标准库下不存在,这时精确的相互转换就无法执行,但是仍然有默认字符转换。 -- 6. VC语言,当定义了宏 _UNICODE 后,_T系列宏或函数,以`宽字符`承载UTF16编码。 TinyXml如何提供`宽字符`函数...
通过理解Unicode编码的基本概念,使用MFC提供的工具进行编码转换,并结合支持Unicode的正则表达式库,我们可以实现对汉字的精确匹配和处理。在实际编程中,这是一项基础但至关重要的技能,尤其在处理多语言文本时...
4. **文化遗产保护**:在数字化传统文化遗产时,精确的笔画顺序信息对于保留书法艺术的精髓至关重要。 #### 五、优化与改进 根据描述,这份表目前还没有经过很好的整理,这意味着它可能不是最方便使用的格式。为了...
在编程或文本处理中,这些代码点可以用来精确地插入或查找特定的符号。 了解这些编码表对于开发者来说至关重要,尤其是处理多语言环境或者中文字符时。例如,当开发一个支持中文的网站,理解GB2312和Unicode的区别...
总的来说,mkvtoolnix-unicode-5.2.1是一款功能强大的mkv编辑套件,无论你是想要混流不同媒体,还是需要进行精确的轨道裁剪或格式转换,它都能提供专业的解决方案。借助这个工具,你可以更加自如地管理和编辑mkv文件...
在计算机科学中,十六进制常用于表示二进制数据,因为每4位二进制可以精确地转换为1位十六进制,使得长的二进制序列更易于阅读和理解。 该工具的特性在于能够处理两种类型的字符串转换: 1. ANSI到十六进制:将使用...