在实际编程中经常会碰到需要读取一个文本文件的内容并将其显示到程序中的情况。如果文件中所有的内容都以ASCII方式编码固然简单(通常包含英文字母和 数字的文件,比如readme之类),但遇到包含其他语言字符,如中文和日文之类就必须在显示之前知道其编码方式。这是因为很多程序在显示文本内容时只接 受UNICODE,故我们必须对非UNICODE的编码方式进行转换。由于谈到UNICODE时通常讨论的都是UCS-2,文中将只对UCS-2文件进行 分析。
本文提供了针对UCS-2 Little Endian,UTF-8和GB2312三种方式的文本文件进行编码识别的方法:
1. UCS-2文件
UCS-2 Little Endia文件以FF FE开头,所以如果一个文件以该标志开头,可以判断出其为UCS-2 Little Endian编码。类似的,UCS-2 Big Endia文件以FE FF开头。当读取UCS-2编码的大文件时,如果因为内存限制而无法一次性将所有内容都读出来的话,就需要分批读取。由于UCS-2是长度固定的编码方式 (两个字节表示一个UNICODE字符),因此只要保证每次都采用偶数长度的缓冲区进行读取,转换就不会出现乱码。
2. UTF-8文件
标 准UTF-8编码的文件是以EF BB BF开头,如果读到该标志,则可以以UTF-8方式进行UCS-2的转码。但
是当程序读取部分内容进行编码的时候则与UCS-2方式有很大的不同!根据规 范,采用UTF-8方式进行编码的字符可以有从1到6个字节的不等长度。因此程序必须从缓冲区末尾开始判断最后一个UTF-8字符出现的位置,以防出现只 包含字符的部分内容从而导致转码失败。
UTF-8的编码规则如下表所示:
UCS-2取值范围 UTF-8编码格式
0x00000000 - 0x0000007F 0xxxxxxx
0x00000080 - 0x000007FF 110xxxxx 10xxxxxx
0x00000800 - 0x0000FFFF 1110xxxx 10xxxxxx 10xxxxxx
0x00010000 - 0x001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
数字转unicode编码0x00200000 - 0x03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0x04000000 - 0x7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
因此逆向查必须到以下信息以确定UTF-8字符的开始字节:
ASCII兼容的字符。这种字符的UTF-8编码值小于0x7F
非ASCII字符的UTF-8编码中的第一个字符总是在范围0xC0到0xFD。如果到此范围内的字符,则可以确定一个UTF-8字符的开始。另外第一个编码的字节中1的个数指定了该字符总共的字节数。
这样就可以确定缓冲区的结尾是否包含了一个完整的UTF-8字符。如果只是部分包含,则应该将该字符去除,否则转换出的结果会有乱码。
3. GB2312文件
GB2312 为简体中文汉字的编码方式,在网络上很常见。GB2312编码的字符可以有一个或两个字节。其中和ASCII兼容的部分都占用一个字节。每个汉字由两个汉 字表示。GB2312的编
码范围是0xA1A1-0x7E7E,去掉未定义的区域之后可以理解为实际编码范围是0xA1A1-0xF7FE。由于使用 GB2312编码的文件不像UCS-2或UTF-8一样使用特殊的标志,因此很难判断其编码方式。当然也可以采取猜测的方式,例如对于非ASCII的双字 节字符,其第一个字符处于0xA1到0x7E的范围之内。但这种方式并不保险,容易和其他编码方式冲突。
总之,对于不同编码方式的文件,除非有特殊的标志可以标示,否则只能采用猜测之类的办法,并且不能保证每次成功。估计只有等到未来UNICODE能够一统天下的时候才不会再有这些问题。:)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论