【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】

前言

本文起因于一次我使用WPS的表格另存为功能导出为TXT文本,如下图所示:

WPS 提示保存的文本文件的类型为 Unicode ,事实上这句提示很废话。

因为众所周知,Unicode 只是一套编码标准,而不是具体的编码实现,简而言之只是提供了二进制与具体字符之间的对应关系。相信在实际开发中应该没有人在程序中指定编码格式为 Unicode 吧。

我在第一次读取导出的 txt 文件时是尝试的 utf-8 编码,代码如下:

const fs = require('fs')
fs.readFile('文本.txt',{encoding: 'utf8'},(err, data) => {
console.log(data)
})

没想到打印输出的全是乱码,没事,换个编码方式再尝试下。

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)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】

终于搞明白Unicode,ASCII,UTF8,UCS2编码是啥了的更多相关文章

  1. vue-router 路由元信息 终于搞明白了路由元信息是个啥了

    vue-router 路由元信息:https://blog.csdn.net/wenyun_kang/article/details/70987840 终于搞明白了路由元信息是个啥了:https:// ...

  2. ASCII,Unicode和UTF-8字符编码

    ASCII码 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte).也就是 ...

  3. ASCII、Unicode、UTF-8字符集编码

    ASCII码 计算机内部,所有信息都是由二进制的字符串表示 每一个二进制位有“0”.“1”两种状态,因此8个二进制位可以表示256个状态,每个状态代表一个符号就是256个符号,从0000000到111 ...

  4. unicode ansi utf-8 unicode_big_endian编码的区别

      随便说说字符集和编码  快下班时,爱问问题的小朋友Nico又问了一个问题:  "sqlserver里面有char和nchar,那个n据说是指unicode的数据,这个是什么意思.&quo ...

  5. unicode 和 utf-8字符编码的区别

    作者:于洋链接:https://www.zhihu.com/question/23374078/answer/69732605来源:知乎著作权归作者所有,转载请联系作者获得授权.   原文:unico ...

  6. unicode 和utf-8,GBK编码

    说到编码,得先从ASCII编码讲起.ASCII编码是由美国人发明,美国的字符不超过255个,所以ASCII编码使用了8bit 即一个字节来存储字符.由于汉字的数量远超255个,所以中国自己发明了一个G ...

  7. 3-7 彻底搞清楚unicode和utf8编码

  8. 深入 Python 解释器源码,我终于搞明白了字符串驻留的原理!

    英文:https://arpitbhayani.me/blogs/string-interning 作者:arpit 译者:豌豆花下猫("Python猫"公众号作者) 声明:本翻译 ...

  9. Windows下ANSI、Unicode、UTF8字符编码转换

    主意:输入字符串必须是以'\0'结尾,如果输入字符串没有以'\0'结尾,请手动设置,否则转换会有错误. unsigned int EncodeUtil::AnsiToUcs2( char* pAnsi ...

随机推荐

  1. noip2019(普及组) 公交换乘 (不剪枝见祖宗题)

    luogu题目传送门 其实就是一道普普通通的模拟题,但是1e5的数据让很多不看数据范围和不加优化的小伙伴们莫名其妙的T了.(包括我) 因此,论减枝的重要性!! 于是乎,最重要的一点也就出来了.早就过期 ...

  2. @Transactional 注解失效场景

    @Transactional可以用在接口.类.类方法上. 作用于类:当把@Transactional注解放在类上时,表示该类的所有public方法都配置了该事物注解. 作用于方法:表示该方法配置了事物 ...

  3. Java实现 LeetCode 820 单词的压缩编码(暴力)

    820. 单词的压缩编码 给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A. 例如,如果这个列表是 ["time", "me", & ...

  4. Java实现 LeetCode 645 错误的集合(暴力)

    645. 错误的集合 集合 S 包含从1到 n 的整数.不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复. 给定一个数组 n ...

  5. Java实现 LeetCode 257 二叉树的所有路径

    257. 二叉树的所有路径 给定一个二叉树,返回所有从根节点到叶子节点的路径. 说明: 叶子节点是指没有子节点的节点. 示例: 输入: 1 / \ 2 3 \ 5 输出: ["1->2 ...

  6. java中Calender类的详细用法(详解)

    一. 如何创建 Calendar 对象 Calendar 是一个抽象类, 无法通过直接实例化得到对象. 因此, Calendar 提供了一个方法 getInstance,来获得一个Calendar对象 ...

  7. Java实现复数运算

    1 问题描述 编程实现两个复数的运算.设有两个复数 和 ,则他们的运算公式为: 要求:(1)定义一个结构体类型来描述复数. (2)复数之间的加法.减法.乘法和除法分别用不用的函数来实现. (3)必须使 ...

  8. MySQL基本DML

    DML: 数据操纵语言, 主要用来向数据库中添加. 删除. 修改数据用的.在开发中经常会用到,所以,在此也小小总结一下: CREATE DATABASE db2 DEFAULT CHARSET UTF ...

  9. 获取ip地址,并根据ip获取当前省份

    <script src="http://pv.sohu.com/cityjson?ie=utf-8"></script> //methods里面 // 获取 ...

  10. 小师妹学JavaIO之:文件File和路径Path

    简介 文件和路径有什么关系?文件和路径又隐藏了什么秘密?在文件系统的管理下,创建路径的方式又有哪些?今天F师兄带小师妹再给大家来一场精彩的表演. 文件和路径 小师妹:F师兄我有一个问题,java中的文 ...