为什么要写这个东西
今天要写的一个小程序用来合并几十个文本文件,然后呢我本以为用C++半小时就可以搞完了,但没想到合并VS工程的xml格式的配置文件总是出现一些方块乱码(长得就像扑克牌的方块一样)。百撕不得骑姐,于是我准备晚上回来仔细查一查然后写个总结。当然,充实自己的博客也是个主要目的。
字符,字符集,字符编码的联系
这三者的定义:
字符(Character)是指计算机中使用的字母、数字、字和符号,包括:1、2、3、A、B、C、~!·#¥%……—*()——+等等, 是类字形单位或符号的基本信息。
字符集(Character set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。
字符编码(英语:Character encoding)也称字集码,是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。
在计算机技术发展的早期,如ASCII(1963年)和EBCDIC(1964年)这样的字符集逐渐成为标准。但这些字符集的局限很快就变得明显,于是人们开发了许多方法来扩展它们。对于支持包括东亚CJK字符家族在内的写作系统的要求能支持更大量的字符,并且需要一种系统而不是临时的方法实现这些字符的编码。
于是出现了 ANSI,GB2312,GBK,Big5, Unicode(与UCS字符集关系密切),UTF-8,UTF-16,UTF-32,Base64等等。
更加详细且清楚的解释请移步Jim Liu的《编码歪传——基础篇》。
一般处理字符的工作流程
推荐使用UTF-8来进行字符存储,但由于很多系统或者软件会产生一些使用其他字符编码的文件,比如我经常用的VS 2013的代码文件中的中文注释在UTF-8下都是乱码,这时候需要转换到GBK进行读取才可以正常显示。
因此,我们进行字符处理的流程需要先判断一下文件使用什么编码,然后将其转换成Unicode,再将其转换成需要的编码(比如把字符显示的数字转换成二进制的数字排在一起)进行存储。
如何判断一个文件的编码格式:首先判断是否是带BOM的UTF-8格式,如果是,则前三个字节为 EF BB BF 。
关于BOM:
BOM(Byte-Order Mark,字节序标记)是Unicode码点U+FEFF。它被定义来放在一个UTF-16文件的开头,如果字节序列是FEFF那么这个文件就是大端序,如果字节序列是FFFE那么这个文件就是小端序。UTF-8本身是没有字节序的问题的(因为它是以单个字节为最小单位),但是Windows里面很多编辑器(比如记事本)会多此一举的在UTF-8文件开头加入EF BB FF也就是U+FEFF的UTF-8编码。
如果不是带BOM的UTF-8格式,则需要判断所有的字节是否符合UTF-8的字节规定:
- 1字节:0xxxxxxx
- 2字节:110xxxxx 10xxxxxx
- 3字节:1110xxxx 10xxxxxx 10xxxxxx
- 4字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
如果出现非法字节则不是UTF-8,那读取则依系统情况而定了。同样的,判断其他字符编码也是可以通过寻找非法字符来判断。但即便是没找到非法字符也不一定说明该文件一定是该字符编码。
对于网络传输来说,最好不同端都约定好默认编码格式。UTF-8兼容ASCII编码,而ASCII是传输英文效率最高的一种,所以一般约定为ASCII编码。
我碰到的问题
带BOM格式的UTF-8的读取:无论用C++字符流还是字节流读取文件后,总是有些字符是乱码,原因已经找到,感谢Jim Liu的文章《编码歪传——番外篇》为我解惑。我读取的有些文件是带BOM标记的,而我讲这些文件的所有字符都存到同一个文件中,就会发现这些BOM是乱码,明天就把这几个字符删掉去。
我们采用xml配置的软件dll调用接口,一旦用文本文档打开后,再关闭就发现解析错误,之前发现文本文档会添加三个字符,于是删掉时候就可以正常解析了。这个问题原因就是我们的解析代码并没有针对BOM进行处理。也就这样吧,我又没权限修改代码,技术总监是傻逼And顽固不化And异想天开And瞎指挥又没将所有代码开放给我们这些开发人员。sad…
记录:一些编码应注意的事项
待补吧……