【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】
前言
本文起因于一次我使用WPS的表格另存为功能导出为TXT文本,如下图所示:
WPS 提示保存的文本文件的类型为 Unicode ,事实上这句提示很废话。
因为众所周知,Unicode 只是一套编码标准,而不是具体的编码实现,简而言之只是提供了二进制与具体字符之间的对应关系。相信在实际开发中应该没有人在程序中指定编码格式为 Unicode 吧。
我在第一次读取导出的 txt 文件时是尝试的 utf-8 编码,代码如下:
const fs = require'fs')
fs.readFile'文本.txt',{encoding: 'utf8'},err, data) => {
console.logdata)
})
没想到打印输出的全是乱码,没事,换个编码方式再尝试下。
fs 模块支持的编码方式包括 utf8、ucs2、ascii、binary、base64、hex。除了utf8 之外,属于 Unicode 编码标准的就是 ucs2 了,换成 ucs2 之后果然得到了正确的输出文字。
问题来了,utf8 和 ucs2 的区别是什么呢?别急,等我慢慢道来。
ASCII编码
先来了解一下编码的“祖宗” ASCII(American Standard Code for Information Interchange)即美国信息交换标准代码。它主要用于显示现代英语,包含了阿拉伯数字、大小写英文字母以及一些常用英式标点符号等。
简单来说,ASCII 编码使用 8 位共 1 字节的二进制数表示字符,范围从 0000 0000 到 0111 1111,可以表示 128 个字符。
Unicode 字符集中对这 128 个字符的编码与 ASCII 是一致的。
UTF-8编码
根据笔者在维基百科上的学习所得,utf-8 是一种针对 Unicode 的可变长度字符编码,也是一种前缀码。它可以用一至四个字节对Unicode字符集中的所有有效编码点进行编码,属于 Unicode 标准的一部分。
UTF-8 编码的规则还可以用下表所表示:
字节数 | 二进制 |
---|---|
1字节 | 0xxxxxxx |
2字节 | 110xxxxx 10xxxxxx |
3字节 | 1110xxxx 10xxxxxx 10xxxxxx |
4字节 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
因此,对 UTF-8 编码中的任意字节,根据第一位是否为 0,可判断是否为 ASCII 字符;根据前二位,可判断该字节是否为一个字符编码的第一个字节;根据前四位(如果前两位均为 1 ),可确定该字节为字符编码的第一个字节,并且可判断对应的字符由几个字节表示;根据前五位(如果前四位为 1 ),可判断编码是否有错误或数据传输过程中是否有错误。
UTF-16编码
【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】
看下维基百科的专业解释:
UTF-16 是 Unicode 字符编码五层次模型的第三层:字符编码表(Character Encoding Form,也称为"storage format")的一种实现方式。即把Unicode字符集的抽象码位映射为16位长的整数(即码元)的序列,用于数据存储或传递。Unicode字符的码位,需要1个或者2个16位长的码元来表示,因此这是一个变长表示。
虽然有些晦涩难懂,但我们依旧可以得出,UTF-16 编码实现只支持通过 2 字节或者 4 字节去表示 Unicode 字符;也可以得出 UTF-16 编码实现不兼容 ASCII 编码(ASCII编码使用 1 字节来进行存储)。
UCS-2编码
我在维基百科的学习中,看到 UCS-2 词条放在了 UTF-16 词条文章下方,并有写明 UTF-16 可看成是 UCS-2 的父集。这是为什么呢?
如果把 UTF-16 支持的 Unicode 字符范围分为两块,即如下表所示:
Unicode范围 | UTF-16编码方式 |
---|---|
U+000 ~U+FFFF |
2 Byte存储 |
U+10000 ~U+10FFFF |
4 Byte存储 |
UTF-16 编码实现和 UCS-2 编码实现的区别就在于 UCS-2 只支持 UTF-16 编码中对U+000
~U+FFFF
范围内的Unicode字符。
对于小于 0x10000 的 UCS 码,UTF-16 编码就等于UCS码。现在如果有软件声称自己支持 UCS-2 编码,那其实是在说它不能支持在 UTF-16 中超过 2 字节的字集。
后记
到此,我们终于搞明白了 UTF-8 和 UCS-2 编码方式的区别,明白了他们虽同属于 Unicode 编码标准实现体系的一部分,但实际对 Unicode 字符编码的实现完全不同。以后,如果再看到存储为 Unicode 文本,你可以尝试下以 UCS-2 格式进行解码,相信大部分情况下都是行得通的。
忽略历史原因,只用下面这一张图就足够解释 Unicode 字符集的编码问题:
最后提供一个查看 Unicode 字符与编码的网站 Unicode字符百科
版权声明
【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】