文本编码

版权声明:本文为Focustc原创文章,转载请注明作者及出处。 https://blog.csdn.net/caozhankui/article/details/50769312

文本编码

  • 文本编码这个问题自三年前就困扰着我,当时是用Python处理多国语言时出现的bug,最后问题解决了,但其中具体逻辑并不懂。后来零零散散接触了不少资料,算是大致弄明白,记录如下。

unicode与ascii等编码方案

ascii

  • ascii编码方案一共规定了128个字符对应的二进制表示,只占用了一个字节的后面7bit,最高位为0
  • 欧洲国家使用128个符号不足以表示所有字母,使用了最高位。因此不同的国家128~255表示不同的符号,并不通用,即为扩展的ascii码,包括ISO-8859-1~15。这些都是单个字节编码。
  • ISO-8859-1
    • ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中
    • ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃
    • Latin1是ISO-8859-1的别名,有些环境下写作Latin-1

gb2312

  • 一种双字节编码,包含6763个汉字

gbk

  • 对gb2312的扩展,可以表示21003个汉字,兼容gb2312

gb18030

  • unicode的一种天朝实现
  • 采用单、双、四字节编码,兼容gb2312

base64

  • base64使用64个可打印字符表示二进制数据。每个单元包含6bit。转换后每76个单元要加上一个换行符。
  • 可打印字符包括:A-Z a-z 0-9以及两个其他不定符号,大部分实现为+ /
  • 将每3个字符编码为4个单元,不足3个的用=补足

unicode

  • unicode试图表示所有的字符
  • 采用unicode的系统、平台有:
    • windows NT及后续系统、java采用utf16作为内置编码
    • .net, mac, kde同样使用unicode
    • utf-8是unix-like操作系统的主要存储编码方案
    • utf-8是html文件最常用的unicode编码
    • XML及其子集XHTML采用UTF-8作为标准字集
  • 编码方案
    • 对每个字符规定了一个码点:code point
    • unicode现在包括17个平面,每个平面最多可以存放65536个字符,也即需要至少21个bit才足够表示所有码点。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0016到1016,共计17个平面
    • 首先的256个字符编码与ISO-8859-1相同
    • 表示方式为U+紧跟十六进制表示。基本平面(BMP U+0000到U+FFFF)中采用四个数字(2byte),16个辅助平面(SMP U+10000到U+10FFFF)中采用5~6个数字
  • 实现方案
    • 实现方案包括Unicode Transformation Format (UTF)和Universal Coded Character Set (UCS)两种
    • unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)
    • utf8:8bit变长编码,详细实现见下一节
    • utf16:16bit变长编码,下有详述
    • utf32:32bit定长编码,完全对应unicode
    • usc-2:2byte定长编码,utf16的子集,JavaScript使用此编码方案。因为不能表示更多字符,后续在此基础上发展出了utf16
    • usc-4:等价于utf32
    • gb18030
  • utf16
    • 对BMP中的字符使用2byte表示,SMP使用4byte
    • BMP从U+D800到U+DFFF之间的码位区段是永久保留不映射到Unicode字符
    • 辅助平面的字符位共有2^20个,也就是说,对应这些字符至少需要20个二进制位。UTF-16将这20位拆成两半,前10位映射在U+D800到U+DBFF(空间大小2^10),称为高位(H),后10位映射在U+DC00到U+DFFF(空间大小2^10),称为低位(L)。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。
    • 对于两个字节,发现它的码点在U+D800到U+DBFF之间,就可以断定,紧跟在后面的两个字节的码点,应该在U+DC00到U+DFFF之间,这四个字节必须放在一起解读。

utf8

  • 采用1~4个byte对unicode进行编码,每个字元只有1byte,不存在字节序问题
  • unicode和utf8编码对应关系

      0000 0000-0000 007F | 0xxxxxxx
      0000 0080-0000 07FF | 110xxxxx 10xxxxxx
      0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
      0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    • 单字节字符的最高有效比特永远为0。
    • 多字节序列中的首个字元组的几个最高有效比特决定了序列的长度。最高有效位为110的是2字节序列,而1110的是三字节序列,如此类推。
    • 多字节序列中其余的字节中的首两个最高有效比特为10
    • 具体为何根据这样麻烦的规则编码呢?一是防止解码出现歧义,二是尽量压缩存储空间。如果学过编码理论或者信息论应当很容易明白。
  • 相对于utf16
    • utf16编码效率/性能较高,字符到字节转换更为方便
    • utf8消耗存储空间较少

文本和IO

  • IO时经常需要对文本进行编解码或编码格式转化
  • 在硬盘文件中:以文件编码格式存储
  • 在内存中:java和c#用utf16
  • 如何显示在屏幕上:显卡驱动(虚拟设备)根据输入字节及编码渲染
  • 网络:按照应用层商定的协议编解码

utf8和BOM

什么是BOM

  • BOM(byte order mark)是为 UTF-16 和 UTF-32 准备的,用于标记字节序(byte order)。
  • utf不同编码实现的BOM定义:
    • UTF-8 EF BB BF
    • UTF-16(大端序) FE FF
    • UTF-16(小端序) FF FE
    • UTF-32(大端序) 00 00 FE FF
    • UTF-32(小端序) FF FE 00 00
  • 对于utf8,没有字节顺序的议题。UTF-8编码过的字节顺序标记则被用来标示它是UTF-8的文件。它只用来标示一个UTF-8的文件,而不用来说明字节顺序。
  • 对于utf16和utf32,用来表示大端还是小段
  • BOM相当于魔数(magic number)
    • 图像文件、ELF文件、class文件都存在魔数
    • linux命令file能根据魔数(libmagic)判断文件类型
    • 文件扩展名更重要的作用是让系统决定当用户想打开这个文件的时候用哪种软件运行,如Windows系统中exe文件是可执行档,doc文件默认用Microsoft Word打开的Word文件。

记事本四种另存为的编码格式

  • ANSI(对于英文系统即ASCII编码,中文系统则为GB2312或Big5编码)
  • “Unicode”(对应UTF-16 LE)
  • “Unicode big endian”(对应UTF-16 BE)
  • “UTF-8”:带 BOM 的 UTF-8

使用utf8不要包含BOM

  • 不含 BOM 的 UTF-8 才是标准形式,在 UTF-8 文件中放置 BOM 主要是微软的习惯(顺便提一下:把带有 BOM 的小端序 UTF-16 称作「Unicode」而又不详细说明,这也是微软的习惯)。微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 ASCII 等编码明确区分开,但这样的文件在 Windows 之外的操作系统里会带来问题。
  • 许多windows程序(包含记事本)会添加字节顺序标记到UTF-8文件。然而,在类Unix系统中,这种作法则不被建议采用。因为它会妨碍到如shell脚本开头的一些重要的码的正确处理。它亦会影响到无法识别它的编程语言。

参考

wiki:BOM
wiki:Unicode

 
 

转载请注明作者:Focustc,博客地址为 http://blog.csdn.net/caozhk,原文链接为 点击打开

猜你喜欢

转载自blog.csdn.net/caozhankui/article/details/50769312