我记得有一次使用emwin的foncnv时,读入pattern文件,出现了好多字符无法识别,当时我就纳闷了,我用的字体是是这种语言的编码的,怎么会无法识别,于是使用windows记事本打开,检查了下文件属性,发现该文件是按照UTF-8形式保存的,心想怪不得。将文件使用UTF-16LE保存,解决了这个问题,我就很好奇这两种有啥区别来着,今天查阅资料大致了解了下两者的区别。
1、字符集与字符编码
字符集是各种文字和符号的集合,常见字符集有ASCII码字符集,Unicode字符集,GB2312字符集,字符编码是将字符集中字符映射成某种形式,以便存储在计算机里。字符集可以认为是一张用数字代表文字或符号的表,字符编码则是这些数字以什么形式存储在计算机存储设备中。
2、字符集发展历史
计算机最早是由欧美人发明的,普遍使用的是ASCII字符集,该字符集以使用0-127(0x00-0x7F)表示欧美人常用的英文字符和符号,并且留了128个(0x80-0xFF)的空白字符用来扩展其他的字符。
由于计算机走向了全世界,然而全世界国家那么多,每个国家都有自己的文字和语言,128个扩张字符集是远远不够,那么每个国家都需要自己的字符集,假设你在A国编辑的文件中"0x01"在该国表示的是一种意思,在B国"0x01"表示的又是另外一种意思,这样该文件内容在两个国家就有不一样的含义。那么多个国家该如何协同工作呢?Unicode字符集的出现解决了这个问题,Unicode码被称为万国码,大部分国家的字符和符号都有被收纳,到现在Unicode码还在不断增加。
Unicode字符集
Unicode是字符集也就是一张用数字代表文字或符号的表,UTF-8、UTF-16LE、UTF-16BE是Unicode字符集的字符编码,决定了该文件内容以什么形式存储在计算机中.
3、ANSI、UTF-8、UTF-16LE、UTF-16BE区别
下图是windows记事本保存文件时可以选择的编码方式。
实验1
对于一个txt文件中包含 “adc”,让我们看看以不同字符编码方式保存,使用16进制编辑器打开看看有什么区别:
1、ANSI的编码方式和UTF-8编码方式的内容是一样的。
ANSI | NC | UTF-8 | NC | |
---|---|---|---|---|
‘a’ | 61 | ‘a’ | 61 | |
‘d’ | 64 | ‘d’ | 64 | |
‘c’ | 63 | ‘c’ | 63 |
2、UTF-16LE和UTF-16BE
LE是小端存储(低字节在低位,高字节在高位),BE是大端存储(高字节在低位,低字节在高位),可以看出以UTF-16LE编码方式存储的文件由FF FE开头,每个字符使用16bit来进行编码保存,UTF-16BE存储在设备中的形式是和UTF-16LE高低位相反的。
LE | FF FE | BE | FE FF | |
---|---|---|---|---|
‘a’ | 61 00 | ‘a’ | 00 61 | |
‘d’ | 64 00 | ‘d’ | 00 64 | |
‘c’ | 63 00 | ‘c’ | 00 63 |
实验2
一个txt文件中包含中 字让我们看看以不同字符编码方式保存,使用2进制打开看看有什么区别:
通过https://www.qqxiuzi.cn/bianma/zifuji.php这个网站,我们可以查出’中’字的字符编码是
header 1 | header 2 |
---|---|
GB2312编码 | D6D0 |
GBK编码 | D6D0 |
Unicode编码 | 4E2D |
首先看ANSI编码保存的,咱们的windows使用ansi保存默认使用的是GBK编码。如下图所示存储内容为d6 d0和上表中的编码一致,
如下图utf-8是unicode字符集的一种编码方式,照理来说应该也是4e 2d的,怎么会是ad b8 e4呢?接下来分析一波:
如上图所示,该图是utf-8的编码方式,"中"字的Unicode编码是4e 2d,在0x800-0x10000中,所以使用上图中第三行的编码公式。
十六进制 | 二进制 |
---|---|
e4 | 1110 0100 |
b8 | 10111000 |
ad | 10101101 |
打开windows上的计算器,我们来看看4e2d的二进制形式为0100-111000-101101,根据上面的编码方式,可以得到
((e4 & 0x0F)<<12 | ((b8 & 0x3F)<<6) | ((ad & 0x3F)<<0)
= 0100-111000-101101 = 4e2d
最后终于得到了4e2d,为什么要兜这么大的一个圈子呢?因为对于英文来说, 符号和字符比较少,如果都使用UTF16形式保存,就会出现 00 xx 00 xx 00 xx的形式,这样会保存一个字符就会就有一个字节被浪费,于是就有了utf-8这种编码形式,。如果该字符小于等于0x7F的值就会使用像第一个实验一样和ANSI的在内存中的编码方式是一样的。
参考资料:
[1] https://www.qqxiuzi.cn/bianma/zifuji.php
[2] http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html