开源中国

我们不支持 IE 10 及以下版本浏览器

It appears you’re using an unsupported browser

为了获得更好的浏览体验,我们强烈建议您使用较新版本的 Chrome、 Firefox、 Safari 等,或者升级到最新版本的IE浏览器。 如果您使用的是 IE 11 或以上版本,请关闭“兼容性视图”。
UCS 和 UTF-8 编码 - 技术翻译 - 开源中国社区

UCS 和 UTF-8 编码 【已翻译100%】

标签: <无>
oschina 推荐于 4年前 (共 15 段, 翻译完成于 01-26) 评论 14
收藏  
86
推荐标签: 待读

Unicode混乱地有点眼花缭乱。它在很多方面有点让人迷失,但最有趣的也正是为让它良好工作时所带来的复杂性。尽管Unicode协会积极发展着Unicode标准,但使用Unicode时很容易让人遗忘它背后丰富多彩的历史。除了众所周知的Unicode,还有ISO 10646中定义的通用字符集。

如今的Unicode以及ISO的UCS最实用的目的是做相同的事情但却有一个稍微有差别的名字。但一直以来并非总是这样的,刚开始时它们的目的是不同的。原因或许是因为有关联信息,或者是因为某些方面在历史上闪耀过。

Garfielt
 翻译得不错哦!

在这里我就不详谈Unicode的历史了,因为已经有很多人谈过了。如果你感到好奇,可以从以下链接里面了解一下:

需要提出的是,为了明白字符集在某些特定情况下的行为,我们要知道一些相关的基础知识。目前 Unicode 和 ISO 10646 还不是同一个东西,他们有各自独特的规则。比如说,各种编码的命名方式就不一样。  UCS2和UCS4分别是通用字符集(UCS)中代表2字节和4字节编码。UTF格式是后来才制订的,现在UTF仍然代表着Unicode转换格式(Unicode Transformation Format),也代表UCS转换格式(UCS Transformation Format)。

daxiaoming
 翻译得不错哦!

UTF家族

一开始的时候,Unicode是16位编码的,大致相同于UCS2编码(已过时)。 渐渐地Unicode支持的字符越来越多,远远超过16位,固定长度编码就不太适用了。

ISO工作组很早就开发了一个编码标准,用来映射ASCII兼容的字符,也就是UTF-1。但是这个标准有很多严重问题,例如不能确保自己的统一性(lack of self synchronization)。如果你接收到一个可能被截断或者损坏的字符流,你可能完全不能正确解释这个字符串,除非你知道全部(包括截断前)的正确字符串。

1992年,UTF-8 问世(比Unicode 2.0正式面世早几年)。现在 UTF-8 应该是数据交换中使用最多的字符编码。使用 UTF-8 的网站占据了大约 因特网的 80%.  大概是因为 UTF-8 不仅十分实用,也很可靠。

daxiaoming
 翻译得不错哦!

当单元固定长度16位的UCS-2到达容量上限不能支持更多的 Unicode 字符的时候,Unicode协会放弃了UCS-2。这就导致了两件事情的发生:他们必须引入16位的变长编码;同时必须减少编码点(code point)总数,使得UTF-16在特性上与UTF-8兼容。也就是说,如果一个字符流已损坏(或已被截断),你也能接收到(除了截断点外后面的)大部分正确的数据。比如说,如果一个字符不能使用一个16位编码单元来表示,还需要额外的编码单元(很正常,采用了变长编码),则必需保证一切正常运行。如果前面那个编码单元在传输过程中丢失了,剩下的那个编码单元实际上是一个非法字符,是可以被忽略的错误字符。而同一个流的后续字符并不受影响,能正确解释。

daxiaoming
 翻译得不错哦!

为了达到这个目的,他们使用了互补单元(surrogate pair)来编码长于16位的字符。实际上,单个UTF-16编码单元定义为2字节或者4字节长,不会有超过4字节的。这样的话,一个编码单元就可以储存 65536 个字符。超出这个范围的字符,就会使用2个编码单元,每个编码单元的数据都经过处理,使得彼此之间都是唯一的。如果单独对互补单元进行处理,那么将发现他们是不完整的字符。这个方法可行的关键是:前互补单元保留了DC00到DF00范围,后互补单元保留了D800到DBFF范围。这样导致的结果是UTF-16可表示的总字符个数是UTF家族中最少的。

daxiaoming
 翻译得不错哦!

UTF-32和之前的UCS-4编码一样,也是固定编码单元长度的。为什么UTF-32能保持固定长度?现在UTF-16是容量最小的UTF编码,它规定了编码点总数为 1112064,也就确定了 Unicode 或 ISO 10646所能定义的字符总数。既然 Unicode 现在只使用了 0 到 10FFFF 范围,UTF-32看起来是不是很鸡肋?拥有32位的编码单元长度,却只使用了21位,是不是有些浪费空间?

UTF-8的编码单元最多使用了31位,不会超过32位。所以UTF家族在最差情况下是一样的:

  UTF-8 UTF-16 UTF-32
最大编码点 10FFFF 10FFFF 10FFFF
编码单元长度 8 位
16 位 32 位
字节依赖 no yes yes
字符占用最少字节 1 2 4
字符占用最多字节 4 4 4

很多人以为UTF-8在最差情况下将占用超过4字节的空间,这其实是错的,至少目前是错的。因为 UTF-16 制订出来了,而且 Unicode 也没有收录超过 1112064 个字符。

daxiaoming
 翻译得不错哦!

选用哪个编码?

毫无疑问,UTF-8看起来是最好的编码。UTF-32显然不行,浪费了大约40%的空间。UTF-8不是字节依赖的,这也是个突出优点。另外,C语言中也可以使用UTF-8(也就是说它是向后兼容的)。在最差情况下,UTF-8占用的空间和其他UTF编码是一样的。

深入调查之后,根据具体语言的不同,UTF-16可能是更高效的储存编码。例如日本语,使用UTF-16会比UTF-8更高效。大部分日本语字符在使用UTF-16储存的时候,只需要使用一个编码单元(2字节);但是如果使用UTF-8的话,就需要占用3字节的空间。

daxiaoming
 翻译得不错哦!

但是如果日本文字夹杂到ASCII字符里,情况就不一样了。比如说,XML或HTML文档包含了大量嵌入的控制字符(基本上都是ASCII字符),这个时候使用UTF-8就高效很多了(非压缩的情况下)。日本语维基百科的首页使用UTF-8保存只需92KB,UTF-16的话则需要166KB。

当然,总的来说UTF-8应用范围很广。我很少看到UTF-16编码的文档,除了 Windows 用户使用记事本创建保存的文档之外基本没看到。

daxiaoming
 翻译得不错哦!

内部编码

但是当内部编码使用Unicode时问题就没那么简单的了,并且在这个问题上也有过不同的意见。

内部编码使用最广的是UTF-8和UTF-16。Java, C# and Objective C (以及Windows API),这些内部编码都是使用UTF-16。UTF-16 的好处是它允许你在基础平面内方便使用绝大多数的数据。这就意味着像strlen()这样的函数既要返回的字节数也要返回字符数。

在很长的时间内,并没有许多关于内部编码使用UTF-16的争论。很长时间内除了很多c程序,仅仅只有Perl语言使用UTF-8作为内部编码。但是现在Ruby,GO以及Rust已经开始使用UTF-8作为内部编码了。当然Ruby可以使用不同的字符编码,但是UTF-8是使用最广泛的一个。

fmxzhou
 翻译得不错哦!

统一访问的重要性

那 UTF-16 为什么这样流行?

一般人都认为,UTF-16最大的卖点是可以直接定位字符。如果全部编程语言都使用21位精度来表示完整的Unicode字符的话,这是没有问题的。不幸的是,C# 和 Java 都不支持。 Java 不支持直接使用UTF-16尚可原谅,因为它诞生得很早,字符串的表示方式也不一样。但 C#不支持UTF-16就说不过去了。

Rust 和 Go 对UTF-16的直接支持则要好得多。虽然它们都默认使用 UTF-8 编码来表示字符串,但是同时也提供了32位数据类型来表示 UTF-16 (Go 语言中的rune,rust中的char)。 在这两种语言中,你都可以遍历整个字符串中实际的Unicode字符。很多情况下,遍历操作足够了。例如说,文本分析通常只需要同时检查一个或者两个字符。

daxiaoming
 翻译得不错哦!
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们
评论(14)
Ctrl/CMD+Enter

我看过其他的关于Unicode和ANSI编码的文章,例如:http://blog.csdn.net/fmddlmyy/article/details/1510189
能清晰的看懂在讲什么,但是看这个,说实话,不知所云。
这个不是入门级的文章,不会去介绍那些基本概念的。只是详细说了一下 UTF-8 的优点,建议大家多采用 UTF-8 编码。
乱啊。。。不想搞懂了。真没那个精力!
理解了为何国家把GBK列为强制简体汉字标准的原因。
根据康熙字典的部首来编排汉字的方式确实比较out
为啥?
UTF-8是编码方式. UCS 是码表. 计算机处理信息, 哪怕是asc编码,都只是数字. 对应的内容是码表指定的. 编码转换的时候. 更多的是查找码表. UCS 中对应的一个字形, 在不同的编码中,有不同的表示.

简单点理解, UCS 对应的字形是一一对应关系. 一个字形有一个唯一的U编码. 但可能有多个UTF-8编码与之对应.

引用来自“魏曼奇”的评论

理解了为何国家把GBK列为强制简体汉字标准的原因。
根据康熙字典的部首来编排汉字的方式确实比较out

为啥?
那种方式是繁体决定简体,大陆官方不接受。
GBK是建立在GB2312基础上的。GB2312的汉字排列是根据拼音、笔画、字频(一二级字库)来排列。
在那个存储资源比较稀缺的年代,仅仅不到7000个汉字就能涵盖汉字99%左右的使用,3000个汉字(一级字库)就能涵盖95%以上的汉字使用。抛弃GB2312就等于否定了大陆官方搞的汉字信息化建设的全部历史,这从政治上是不能接受的。
作为康熙字典,在汉语言学界是有争议的,主要是对汉字的拆解上。况且那种部首方式适合繁体汉字。对简体汉字不太适合。

引用来自“魏曼奇”的评论

那种方式是繁体决定简体,大陆官方不接受。
GBK是建立在GB2312基础上的。GB2312的汉字排列是根据拼音、笔画、字频(一二级字库)来排列。
在那个存储资源比较稀缺的年代,仅仅不到7000个汉字就能涵盖汉字99%左右的使用,3000个汉字(一级字库)就能涵盖95%以上的汉字使用。抛弃GB2312就等于否定了大陆官方搞的汉字信息化建设的全部历史,这从政治上是不能接受的。
作为康熙字典,在汉语言学界是有争议的,主要是对汉字的拆解上。况且那种部首方式适合繁体汉字。对简体汉字不太适合。

我想到了CTeX

Unicode编码(十六进制) UTF-8 字节流(二进制)
000000 - 00007F 0xxxxxxx
000080 - 0007FF 110xxxxx 10xxxxxx
000800 - 00FFFF 1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

引用来自“刘地”的评论

引用来自“魏曼奇”的评论

理解了为何国家把GBK列为强制简体汉字标准的原因。
根据康熙字典的部首来编排汉字的方式确实比较out

为啥?

排序问题, 我们平常的思维是是按读音排序的, 不过会有多音字问题. GBK 是按照读音排序的. 部首排序不会有这个问题. 至于那个更合理,,,
说不清楚啊.
排序的不同造成 GBK和 Unicode 转换只能查表.
不理解,只要好用就好了,最好都采用一个标准来搞定,不然这边编写用UTF-8那边现实却用的是GBK,烦死了。

引用来自“魏曼奇”的评论

理解了为何国家把GBK列为强制简体汉字标准的原因。
根据康熙字典的部首来编排汉字的方式确实比较out

GBK是微软搞出来的行业标准而不是国家标准。国标是GB加上数字的组合
这篇文章没提到js内部是使用ucs2编码的,所以兼容性非常好,没有python2k->3k升级带来那么大的兼容问题
顶部