文本文件编码方式的简单识别

 在实际编程中经常会碰到需要读取一个文本文件的内容并将其显示到程序中的情况。如果文件中所有的内容都以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 -  0x0000007F0xxxxxxx
0x00000080 -  0x000007FF110xxxxx 10xxxxxx    
0x00000800 -  0x0000FFFF        1110xxxx 10xxxxxx 10xxxxxx    
0x00010000 -  0x001FFFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0x00200000 -  0x03FFFFFF111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0x04000000 -  0x7FFFFFFF1111110x 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能够一统天下的时候才不会再有这些问题。:)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值