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

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. Android使用 selector 自定义控件背景 (以spinner 为例)

    1. 在drawable中设置背景spinner_style.xml 文件  如图: 2. 在 styles.xml 中添加该背景 3. 最后在 spinner 控件添加样式 4.参考 http:// ...

  2. Android TV 模拟器启动

    模拟器启动错误 使用IntelCPU的模拟器 http://software.intel.com/en-us/android/articles/intel-hardware-accelerated-e ...

  3. ASP.NET Excel数据导入数据库

    <identity impersonate="true"/> 是指模拟IIS身份验证 導入錯誤時可刪除 protected void btnImport_Click(o ...

  4. java集合之链式操作

    如果用过js/jquery.groovy等语言,大概对这样的代码比较熟悉: [1,2,3].map(function(d){...}).grep(function(d){...}).join(',') ...

  5. jQuery实现的向下推送图文信息滚动效果

    HTML 我们以新浪微博信息滚动为背景,html中包含了多条微博图文信息,结构如下: <div id="con"> <ul> <li> < ...

  6. C#入门经典(第五版)学习笔记(三)

    ---------------面向对象编程简介--------------- UML表示方法: 1)方框上中下三分 2)上框写类名 3)中框写属性和字段,例如:+Description:string  ...

  7. phpcms(3) V9 常用函数 及 代码整理(转)

    转自http://www.cnblogs.com/Braveliu/p/5103918.html 常用函数 及 常用代码 总结如下 <;?php //转换字符串或者数组的编码 str_chars ...

  8. 利用C#的反射机制动态调用DLL类库

    最近由于业务要求,需要动态调用DLL类库,所以研究了一下,感觉还好也不太难,今天就把自己理解的写了一个小例子(已经通过VS2005跑通),供大家一起研究和探讨,有理解不当的地方还请高手们多多指正,谢谢 ...

  9. DOM对象控制HTML无素——详解1

    getElementsByName()方法 返回带有指定名称的节点对象的集合. 语法: document.getElementsByName(name) 与getElementById() 方法不同的 ...

  10. PHP数据学习-二维数组【3】

    <?php // $project = array( // array("bai",12,23.0), // array("zeng",34,12.0), ...