Wons' Blog

个人博客

后端程序猿 - Python / C++ / Java


回首向来萧瑟处,也无风雨也无晴

字符编码简介

1. ASCII码

ASCII (American Standard Code for Information Interchange, 美国标准信息交换代码),是基于拉丁字母的一套编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统。 单个字节可以表示256个不同的字符,不过 ASCII 只使用了其中低于\x80(即最高位字节为0)的一半来表示所有的英文字符以及一些控制字符,因此 ASCII 码的实际取值范围为0x000x7f之间,一共128个字符。

2. 多字节字符集MBCS

ASCII字符集中只含有英文字符,不能满足其他语言的需求。于是很多语言就制定了一套自己的编码,由于 ASCII 是单字节的,能表示的字符数量太少,因此这些编码很多都使用多个字节来表示单个字符。例如 GBK 等。 这些编码的规则都比较相似: 如果第一个字节是\x80以下,则仍然表示 ASCII 字符,而如果是\x80以上,则跟下一个字节一起(共两个字节)表示一个字符。

IBM发明了一个叫Code Page的概念,将这些编码都收入囊中并分配页码,GBK 是第936页,也就是CP936。所以,也可以使用CP936表示 GBK

这些各种语言自己制定的编码统称 MBCS (Multi-Byte Character Set)。目前都是用了双字节,所以有时候也称为 DBCS (Double-Byte Character Set)。必须明确的是,MBCS 并不是指某一种特定的编码,Windows里根据你设定的区域不同,MBCS 代表不同的编码,而Linux里无法使用 MBCS 作为编码。在Windows中你看不到 MBCS 这几个字符,因为微软使用了 ANSI 这个称呼,记事本的另存为对话框里编码 ANSI 就是 MBCS 。在简体中文 Windows 默认的区域设定中,ANSI 代表 GBK 编码。

3. Unicode

由于各种不同的 MBCS 编码互相不兼容,使用、转换起来很不方便,于是便有了 Unicode

Unicode (万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。

Unicode 发展由非营利机构统一码联盟负责,该机构致力于让Unicode方案替换既有的字符编码方案。因为既有的方案往往空间非常有限,亦不适用于多语环境。

Unicode 备受认可,并广泛地应用于电脑软件的国际化与本地化过程。有很多新科技,如可扩展置标语言、Java编程语言以及现代的操作系统,都采用 Unicode 编码。

最初的Unicode标准UCS-2使用两个字节表示一个字符,一共能表示 256×个字符,不久后又有人觉得还是太少了,于是出现了用4个字节表示一个字符的UCS-4标准。

UCS (Unicode Character Set)仅仅是字符对应码位的一张表而已。具体如何传输和储存字符则是由 UTF (UCS Transformation Format)来指定。

一开始直接使用 UCS 的码位来保存字符,这就是UTF-16,比如这个字的码位是6C49,则直接使用\x6C\x49保存(UTF-16-BE,BE指Big Endian),或是倒过来使用\x49\x6C保存(UTF-16-LE,LE指Little Endian)。

但是这种保存方式在保存英文字符时,会浪费很多存储空间( ASCII 保存一个字符只需要一个字节),于是变有了 UTF-8

UTF-8 是一种变长并且兼容 ASCII 的字符编码,在 UTF-8ASCII 字符仍然使用相同的一个字节表示,这使得原来处理 ASCII 字符的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字的应用中,优先采用的编码。

UTF-8 使用一至六个字节为每个字符编码(尽管如此,2003年11月 UTF-8RFC 3629重新规范,只能使用原来 Unicode 定义的区域,U+0000U+10FFFF,也就是说最多四个字节):

  • 128个 US-ASCII 字符只需一个字节编码(Unicode 范围由U+0000U+007F).
  • 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码( Unicode 范围由U+0080U+07FF)。
  • 其他基本多文种平面( BMP) 中的字符(这包含了大部分常用字,如大部分的汉字)使用三个字节编码(Unicode 范围由U+0800U+FFFF)。
  • 其他极少使用的 Unicode 辅助平面的字符使用四至六字节编码(Unicode 范围由U+10000U+1FFFFF使用四字节,Unicode 范围由U+200000U+3FFFFFF使用五字节,Unicode 范围由U+4000000U+7FFFFFFF使用六字节)。

对上述提及的第四种字符而言,UTF-8 使用四至六个字节来编码似乎太耗费资源了。但 UTF-8 对所有常用的字符都可以用三个字节表示,而且它的另一种选择,UTF-16 编码,对前述的第四种字符同样需要四个字节来编码,所以要决定 UTF-8UTF-16 哪种编码比较有效率,还要视所使用的字符的分布范围而定。

另外值得一提的是 BOM (Byte Order Mark)。我们在储存文件时,文件使用的编码并没有保存,打开时则需要我们记住原先保存时使用的编码并使用这个编码打开,这样一来就产生了许多麻烦。UTF 则引入了 BOM 来表示自身编码,如果一开始读入的几个字节是其中之一,则代表接下来要读取的文字使用的编码是相应的编码:

BOM BYTES
BOM_UTF8 \xef\xbb\xbf
BOM_UTF16_LE \xff\xfe
BOM_UTF16_BE \xfe\xff

并不是所有的编辑器都会写入 BOM ,但即使没有 BOMUnicode 还是可以读取的,只是像 MBCS 的编码一样,需要另行指定具体的编码,否则解码可能会失败。 绝大多数编辑器在没有BOM时都是以 UTF-8 作为默认编码读取。即使是保存时默认使用 ANSI (MBCS)的记事本,在读取文件时也是先使用 UTF-8 测试编码,如果可以成功解码,则使用 UTF-8 解码。这个别扭的做法造成了一个BUG:如果你新建文本文件并输入姹塧然后使用 ANSI 保存,再打开就会变成 汉a

参考资料:

最近的文章

常用搜索引擎技巧

指定站内搜索使用site指定在某网站内搜索例如只在知乎中搜索 liuwons : liuwons site:zhihu.com精确匹配使用双引号来指定精确匹配单词或短语如精确搜索 liuwons : "liuwons"模糊搜索使用星号代替一个单词进行模糊搜索例如"a * saved is a * earned"会搜到如下结果:A penny saved is a penny earned指定索搜结果不包含某些内容使用减号指定搜索结果中不包含某些内容例如 liuwons -site:gith...…

Search Engine继续阅读
更早的文章

nginx实现请求转发

nginx实现请求转发反向代理适用于很多场合,负载均衡是最普遍的用法。nginx 作为目前最流行的web服务器之一,可以很方便地实现反向代理。nginx 反向代理官方文档: NGINX REVERSE PROXY当在一台主机上部署了多个不同的web服务器,并且需要能在80端口同时访问这些web服务器时,可以使用 nginx 的反向代理功能: 用 nginx 在80端口监听所有请求,并依据转发规则(比较常见的是以 URI 来转发)转发到对应的web服务器上。例如有 webmail , web...…

nginx继续阅读