文件字符编码概述

作为一个程序员,不可避免要经常与字符编码打交道。代码乱码、数据乱码、报文乱码也是时常遇到。近期生产上也出现了乱码、非法字符问题,趁着这个机会对字符编码进行下总结。

1.文件内容格式概述

首先大家应该理解:文件其实是一系列的二进制流,界面展示(或程序执行)相当于对这些二进制流的一种转义。理解这一点再考虑后面的问题就简单多了。

对于文件来说里面可以存放任何内容,例如文件可以存放文本、图片、音乐、视频甚至是程序二进制可执行文件。不同的文件需要不同的软件才能进行查看,例如一般的文本可以用记事本、UltraEdit、vim等来查看;图片可以用系统自带的看图工具打开,但编辑则需要Photoshop等专业工具;音乐和视频文件也类似。为了进一步标识哪些文件可以用什么软件打开或编辑,就有了文件拓展名(后缀),例如.txt、.pdf、.mp3等等,文件拓展名只是一个标识,并不影响具体的文件内容和展示。

下面再说下二进制与文本文件的区别:文本文件是指你能够直接用文本编辑器打开,能直接读得懂。二进制文件则需要特定的软件来读取。

2.文本文件编码问题

文本文件是我们最常遇到的文件格式,它们的后缀有很多种比如txt,log,rb,java,h,cpp等等,当然也不局限于这些后缀。刚也说过了后缀并不影响文件的内容和展示,一个没有后缀的文本文件也可以正常打开和查看。文本文件其实也是一系列的二进制流,但它是遵循某个编码标准的(另外还有BOM等特殊规定),常见的编码标准有ASCII、GBK、UTF-8等等。这些编码定义了二级制和字符之间的映射关系,例如汉字“中”的UTF-8编码为E4 B8 AD,它的GBK编码为D6 D0。编码可以参考这些博文1 2

假设文件是用GBK编码写的,但是当成UTF-8格式来读,得到的结果肯定是不对的,可能会有乱码或者天书文字。当然了,现在编辑器还是挺智能的,它们一般能识别出文件使用的编码,所以看上去没什么问题。遇到乱码问题需要做两件事:1.确定文件使用的正确编码格式;2.利用iconv等编码转换工具将文件转换为其他你指定的编码;或者指定让编辑器采用和文件一致的格式来读取。

大家可能还遇到过一种事情,我的编码选对了,大部分字符都能正确显示,但仍然有部分是?、[]或是其他乱码,这种一种可能是文件本身有问题,另一种是字符集的问题。比如Unicode定义了U+00000-U+10FFFF所有的字符集(其中U+D800-U+DFFF为UTF-16的代理对字段),但是一般的字体、软件仅支持U+0000-U+FFFF中的常用字符。对于这之外的即使是合法的字符,也不支持显示。

3.不同程序对于字符编码的支持

不同程序对于字符编码的支持各异,下面分别以java和ruby为例进行简单说明:

Java编码

在Java内部支持unicode编码,严格地说它采用的是UTF-16编码,对于BMP字符严格支持,但对于增补字符U+100000-U+10FFFF支持不佳,在调用函数时需小心。具体参见3 4

在java中常见的中文string,length方法和substring方法都能得到正确的结果,但是对于增补字符会有问题,可能出现半个字的问题。Java中的length对于U+0000-U+FFFF的字符会认为是长度为1,但对于增补字符会认为是2。

String str = "今天天气很好" ;
Assert. assertEquals(6, str.length());
Assert. assertEquals("天气", str.substring(2, 4));
Assert. assertEquals(2, "\uDD1E\uD834".length());//增补特殊字符
Assert. assertEquals("\uD834", "\uDD1E\uD834".substring(1, 2));

Ruby编码

在ruby中1.9+采用原始文件的编码,可以在文件、io等进行指定,字符串长度等方法对于字符集可以很好的支持,对于增补字符也能得到正确的结果。具体参见5

"今天天气很好".length   =>  6
"\u{1DD1E}".length  => 1

4.其他的编码规范

URL编码:

在URI规范中存在一些保留字符,如:/?&=@%等,这些字符如果要作为参数使用而不是作为特殊字符使用,必须在%字符后以十六进制数值表示,例如%3A表示:;另外由于URL只能使用ASCII编码,所以对于中文等需要按照网页的编码格式进行编码,例如“中”应表示为%E4%B8%AD;另外URL 不能包含空格,通常使用 + 来替换空格。

XML编码:

在xml中对于特殊字符如 &<>’" 也需要进行转义。例如使用&lt;来表示<。在报文或是文件中需要对于这些特殊字符进行处理,如转义或是加上<![CDATE[ ]]>。否则在读取或保存是会出错。

注:严格地讲,在 XML 中仅有字符 “<”和”&” 是非法的。省略号、引号和大于号是合法的,但是把它们替换为实体引用是个好的习惯。 在XML的头部可以指定文件的编码方式,包括gbk,utf-8等,这些字符并不需要特殊转义,只要和声明的编码一致即可。

HTML编码:

和xml一样,对于&<>’”也需要进行转义处理。另外html对于其他一些不易输入的特殊字符可以使用特殊编码6 7。对于文件中的字符只要和文件头中声明的字符集一致即可。

参考资料:

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《ITechLib》

留言:

测试评论显示

(lesstile enabled - surround code blocks with ---)