blog:misc:charactor_encoding

字符编码

ASCII

ASCII is the American Standard Code for Information Interchange ASCII编码用一个字节来表示一个字符, 总共定义了128个字符的编码(包括大小写的英文字母,特殊符号,控制字符)

Unicode

由于不同的国家使用不同的字符 即使都采用256个符号的编码方式,不同的编码方式会导致相同的数字可能对应不同的符号

有的语言使用的符号远远超过了256个字符,所以就必须采用多个字节来表示一个符号 例如简体中文常见的编码方式是GB2312

如上所述,世界上存在多种编码方式,同一个二进制可能被解释为不同的符号, 因此要查看一个文件,就必须要知道字符的编码方式,否则用错误的编码方式就会出现乱码 并且如果一个文件里面使用了多种语言,那么由于编码方式不同,也会出现乱码

为了解决以上问题,就定义了一种编码,可以将世界上所有的符号都纳入其中, 每个符号都包含一个独一无二的编码, 这就是Unicode 例如:

U+0041表示英语的大写字母 'A'
U+4E2D表示汉字 '中'

unicode 只是一个符号集, 只规定了符号的二进制代码,却没有规定这个二进制代码该如何存储 比如汉字 '国'的unicode编码为 0x56fd, 至少需要用2个字节才能存储,表示其他符号可能需要更多的字节

有如下两个问题需要解决: 1. 如何区分unicode和ascii? 2. 计算机怎么知道3个字节表示一个符号,或者是3个字节分别表示3个符号?

如果统一规定每个字符用4个字符表示,那么每个英文字符都有3个字节为0, 这样极大地浪费存储空间

UTF-8

UTF-8 只是 unicode的一种实现方式之一 UTF-8的特点: 采用变长编码,它可以使用1~4个字节表示一个符号

编码规则: 1. 对于单字节的符号,字节的第一位设为0, 后面7位为这个字符的unicode码

  因此ASCII可以看作UTF-8的子集

2. 对于大于n字节的符号(n > 1)

  第一个字节的前n位都设置为1,第n+1位设为0
  后面的字节前两位一律10
  其余的位用字符的unicode填充
unicode 符号范围 UTF-8编码字节数 UTF-8编码方式
—- —- —-
十六进制 - 二进制
0000 0000 - 0000 007F 1 0xxxxxxx
0000 0080 - 0000 07FF 2 110xxxxx 10xxxxxx
0000 0800 - 0000 FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
0001 0000 - 0010 FFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0020 0000 - 03FF FFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0400 0000 - 7FFF FFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

转换示例: 例如: unicode 0x4F60, 表示中文 '你' 从上表可知 0x4F60 在UTF-8编码下需要用3个字节编码 3字节的UTF-8编码格式为 1110 xxxx 10xx xxxx 10xx xxxx 0x4F60的二进制表示为 0100 1111 0110 0000 填充到3字节的UTF-8格式中得到:

1110 xxxx  10xx xxxx  10xx xxxx
     0100    11 1101    10 0000

1110 0100 1011 1101 1010 0000 即 e4bda0

下面使用iconv 和 xxd 工具来验证:

将unicode转换为UTF-8编码,可用如下命令实现: 例如: unicode 0x4E25

echo "25 4e" | xxd -r -p | iconv -f UNICODE -t UTF-8 | xxd -p
输出结果为: e4b8a5

xxd -r -p的输入字符串为 "25 4e", 低字节在前,高字节在后
输出结果也是第字节在前,高字节在后, 所以 e4为低字节, a5为高字节

echo "604f" | xxd  -r -p | iconv -f UNICODE -t UTF-8 | xxd -p
输出结果为: e4bda0

unicode字节序

对于unicode 0x4F60, 有两个字节0x60和0x4F 如果采用big endian方式存储, 则第一个字节为0x4F,第二个字节为0x60 如果采用little endian方式存储, 则第一个字节为0x60,第二个字节为0x4F

unicode规范定义,每个文件的前面加入两个字节表示编码顺序 如果文件前两个字节分别是 fe ff, 则表示big endian 如果文件前两个字节分别是 ff fe, 则表示little endian

例: 新建一个文本文档,文件内容为 '你', 编码格式为UTF-8

$ cat test.txt 
你
$ file test.txt 
test.txt: UTF-8 Unicode text

转换为unicode编码:

$ iconv -f UTF-8 -t UNICODE  test.txt  > test_unicode.txt
$ file test_unicode.txt 
test_unicode.txt: Little-endian UTF-16 Unicode text, with no line terminators
$ xxd -g 1 test_unicode.txt 
00000000: ff fe 60 4f 0a 00
  • blog/misc/charactor_encoding.txt
  • 最后更改: 2022/01/09 23:04
  • 127.0.0.1