很久以前发在他处的一篇博文,今天翻出来重新整理了一下

Unicode 字符集 共分为 17 个平面(plane), 分别对应 U+xx0000 - U+xxFFFF 的 code points, 其中 xx := 00 - 10。其中第 0 平面不包含为 UTF-16 编码保留的 U+D800 - U+DFFF。第0平面包含了最常用的字符,被成为 Basic Multilingual Plane 或 BMP (基本多语言平面)。

Unicode 在编码上有多种实现,常见的有 UTF-8, UTF-16, UCS-2(已过时), UTF-32(UCS-4)等。

UTF-8 编码

UTF-8是一种变长、多字节编码方式,可以表示所有Unicode字符码点(code point),并且与ASCII兼容。UTF-8使用字节作编码单元(code unit),用一个或多个字节编码一个Unicode字符,其中使用一个字节编码的字符与 ASCII 相同。UTF-8编码中不同含义的字节模式:

  1. 0xxxxxxx ASCII字符
  2. 10xxxxxx 多字节字符的非首编码单元
  3. 110xxxxx 双字节字符的首个编码单元
  4. 1110xxxx 三字节字符的首个编码单元
  5. 11110xxx 四字节字符的首个编码单元
  6. 111110xx 五字节字符的首个编码单元
  7. 1111110x 六字节字符的首个编码单元

例如元符号 U+00A5( ¥ ),二进制表示为 10100101,共8位,因为UTF-8编码除首字节外其它字节都必须以 10 开头,所以每字节有效位为6位,那么 U+00A5 的最后一个字节应该是 10 100101,此外还剩下的两个比特位由双字节字符的首字节模式 110xxxxx 即可完全容纳。 因些U+00A5 符合双字符编码要求,编码结果为 11000010 10100101 即 0xC2B5。

可以看到 UTF-8 实际上是比较浪费空间的,理论上非首编码单元完全可以不必使用固定的 10 前缀,而是利用整个编译单元保存8位字符数据,从而大大减小编码结果的体积。但UTF-8选择了牺牲空间利用率来换取更高的容错能力,当一大段 UTF-8 编码的内容中出现一两个字节的错误时,解码器可以快速跳过错误字符,找到下一个字符的编码首字节(必定以 110, 1110, 11110, .... 打头)

注:一些 Windows 程序在保存 UTF-8 编码文本文件时会在开头添加 0xEF, 0xBB, 0xBF 序列(貌似这个序列在little-endian与big-endian的机器上顺序还是相反的),一般称为 UTF-8 BOM (Byte Order Mark),当然事实上其与字节顺序无关 -- 因为 UTF-8 本身就以字节为单元 -- 而是用于推断文件的编码方式是否为 UTF-8的。 标准并未规定UTF-8这种文件头标识方式,而BOM在标准中是用来判定UTF-16的字符顺序的(而不是编译方式本身,详见下文)。 但由于微软大力推行这种标记方式,致使行业中的各种解码程序不得不与之兼容。

UTF-16

UTF-16 也是变长多字节编码,并可表示所有 Unicode 字符码点(code point),但以双字节(字)为编码单元。UTF-16的编码原则如下:

  1. BMP: 使用一个双字节编码单元,字符码点(code point)的数字值与编码单元的数字值相等一一对应。
  2. 平面 1-10: 使用两个编码单元共四个字节表示一个字符,规则如下:
    1. 字符值减去 0x10000, 结果为 0 - 0xFFFFF 之间20位长的数字,我们暂记为 n 吧。
    2. 取出 n 的前10位,加上 0xD800 结果在 0xD800 - 0xDBFF 之间作为第一个编码单元,也称为前导代理(lead surrogate)。
    3. 取出 n 的后10位,加上 0xDC00 结果在 0xDC00 - 0xDFFF 之间作为第二个编码单元,也称为断后代理(trail surrogate)。

比如字符 U+00A5( ¥ ),属于BMP,编码后为双字节的 0x00A5。

字符 U+201D3 (”3),二进制 10 0000 0001 1101 0011 ,共14个二进制位,不属于BMP,需要使用两个编码单元(4字节)来编码表示, 根据原则2,201D3 - 10000 = 101D3,20位二进制码为 0001 0000 0001 1101 0011 ,前10位为 0001 0000 00 即 0x40,加上 0xD800 得到 lead surrogate 0xD840;后10位为01 1101 0011即0x1D3,加上 0xDC00 得到 trial surrogate 0xDDD3。最后得到UTF-16编码为 0xD840, 0xDDD3。

UTF-16使用双字节编码单元,因些存在字节顺序的问题,可以使用字节顺序标记(Byte Order Mark 或 BOM)来帮助确定字节顺序,即将一个特殊Unicode字符U+FEFF(零宽不断行空白 Zero-width non-breaking space 或 ZWNBSP)置于第一个真正的字符之前, 如果解码程序以自己假定的字节顺序读到了 U+FFFE (这是个保留的非字符值),解码程序应该尝试进行字节交换。 如果没有检测到BOM,标准要求解码程序默认使用 big-endian, 但实际应用大多假定 little-endian, 因为windows默认这样干。字节顺序也可有通过编码名称 UTF-16BE 和 UTF-16LE 区别。

除UTF-16外,UCS-2也是16位编码单元,但不支持双编码单元组合,也就不能表示所有 Unicode 字符。 目前该编码方式已被标记为过时。

UTF-32/UCS-4

这个就不必细说了,编码结果对应Unicode的code point。

C/C++ 中的字符类型与编码方式 [仅个人理解,有待核实] char 类型的字符串一般以代码文件的编码方式处理,比如 UTF-8 保存的 c 代码文件中的 char 字符串使用 UTF-8 编码;而以 GB18030 编码保存代码文件中的字符串使用 GB18030 编码。 而使用 UTF-16 或其它非ASCII兼容的编码保存的代码文件中的字符编码本人未弄清楚。 wchar_t 类型的字符串以 UTF-16(Windows 下) 或 UTF-32(Unix/Linux下) 编码,常量声明方式为 L"string content",即字符串常量前边加L前缀。

Unicode 字符集及UTF-8 UTF-16编码的更多相关文章

  1. zzy:java采用的是16位的Unicode字符集作为编码方式------理解

    java语言使用16位的Unicode字符集作为编码方式,是疯狂Java中的原话. 1,编码方式只是针对字符类型的(不包括字符串类,数值类型int等,这些只是在解释[执行]的时候放到Jvm的不同内存块 ...

  2. 刨根究底字符编码之十——Unicode字符集的字符编码方式CEF

    Unicode字符集的字符编码方式CEF 一.字符编码方式CEF的选择 1. 由于Unicode字符集非常大,有些字符的编号(码点值)需要两个或两个以上字节来表示,而要对这样的编号进行编码,也必须使用 ...

  3. 刨根究底字符编码之十——Unicode字符集的编码方式以及码点、码元

    Unicode字符集的编码方式以及码点.码元 一.字符编码方式CEF的选择 1. 由于Unicode字符集非常大,有些字符的编号(码点值)需要两个或两个以上字节来表示,而要对这样的编号进行编码,也必须 ...

  4. Unicode字符集,utf8编码,base64编码简单了解

    Unicode字符集,utf8编码,base64编码简单了解 Unicode字符集,ASCII,GB2312编码集合等,类似于不同的字典,不同的字符的编码,类似于字典中的字在哪一个页哪一排. 当不同系 ...

  5. 多字节字符集与Unicode字符集

    在计算机中字符通常并不是保存为图像,每个字符都是使用一个编码来表示的,而每个字符究竟使用哪个编码代表,要取决于使用哪个字符集(charset). 多字节字符集: 在最初的时候,Internet上只有一 ...

  6. Unicode规范中的BOM 和 ISO8891-1编码

    Unicode规范中的BOM Unicode规范中有一个BOM的概念.BOM——Byte Order Mark,就是字节序标记.在这里找到一段关于BOM的说明: 在UCS 编码中有一个叫做" ...

  7. C语言:Unicode字符集

    Unicode 也称为统一码.万国码:看名字就知道,Unicode 希望统一所有国家的字符编码.Unicode 于 1994 年正式公布第一个版本,现在的规模可以容纳 100 多万个符号,是一个很大的 ...

  8. 《windows核心编程系列》二谈谈ANSI和Unicode字符集 .

    http://blog.csdn.net/ithzhang/article/details/7916732转载请注明出处!! 第二章:字符和字符串处理 使用vc编程时项目-->属性-->常 ...

  9. 关于Unicode字符集

    最初的unicode编码是固定长度的,16位,也就是2两个字节代表一个字符,这样一共可以表示65536个字符.显然,这样要表示各种语言中所有的字符是远远不够的.Unicode4.0规范考虑到了这种情况 ...

随机推荐

  1. C#内存修改

    先通过 System.Diagnostics.Process类获取想要编辑的进程 调用API [Flags]                    public enum ProcessAccessT ...

  2. oracle 中查看一张表是否有主键,主键在哪个字段上的语句怎么查如要查aa表,

    select a.constraint_name, a.column_name from user_cons_columns a, user_constraints b where a.constra ...

  3. 关于UNION和UNION ALL的区别

    今天在运行程序的时候发现个问题,就是计算和的时候两条数据一样的话自动去除重复的,可是我这个程序需要重复的数据也算进来呀,然后就找原因,最后在sql语句中找到了是union和union all的问题,简 ...

  4. 最终版-perl工具解析数据库的报告文件0120

    ********************需要根据自己的实际环境修改哦**************************** ******************** 1. 收集awr报告样本   a ...

  5. UITextView/UITextField检测并过滤Emoji表情符号

    UITextView/UITextField检测并过滤Emoji表情符号 本人在开发过程中遇到过这种情况,服务器端不支持Emoji表情,因此要求客户端在上传用户输入时,不能包含Emoji表情.在客户端 ...

  6. NSCondition的用法,NSCondication实现线程同步,生产者消费问题实现(转载)

    NSCondition的用法 使用NSCondition,实现多线程的同步,即,可实现生产者消费者问题. 基本思路是,首先要创建公用的NSCondition实例.然后: 消费者取得锁,取产品,如果没有 ...

  7. SGU 128.Snake

    时间限制:0.25s 空间限制:4m 题意: 在一个平面坐标中有N个点,现在要你用这N个点构造一个闭合图形,这个图形要满足以下条件: 1.这个图形要是闭合的:          2.图形上的点只能是给 ...

  8. SGU 163.Wise King

    一道题目长的水题.... 总结就一句话,给出n个(-3~3)的数,一个数m,取任意个数是使这些数的m次幂之和最大. code #include <iostream> #include &l ...

  9. 【POJ1417】【带标记并查集+DP】True Liars

    Description After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda was ...

  10. 初探grunt.js

    package.js { "name": "ttd_v3", "version": "0.1.0", "aut ...