关于字符编码的一些简单思考
在上一篇提到的BOM头,实际上牵扯到文本的编码问题,BOM头是出现在windows下用文本编辑器编写文件后,按照UTF-8的格式下保存文件而我们在编辑php脚本的时候通常是用utf-8的格式保存脚本文件,在这种情况下,我们发现不了bom头的存在。可是如果我们将php的脚本文件按照gbk编码保存我们就能轻易发现bom头的存在,道理很简单
我们先看utf-8的编码规则,utf-8采用的是动态编码,实际上是以字节为单位对unicode(通用码)做的再编码,对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。下图可以大致看出utf8的编码规则。
从编码规则上,我们可以看出bom头0xEF 0xBB 0xBF 符合utf-8指向一个字符的编码规则,那么如果以gbk的编码规则来看bom头,我们再来看看,首先,我们看看gbk的编码规则:
"GBK 亦采用双字节表示,总体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。总计 23940 个码位,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号 883 个。"(来源百度百科);
我们选择带有BOM头的字符串看一下 <?xml version ,通过xxd,我们查看十六进制的编码规则如下efbb bf3c 3f78 6d6c 2076 6572 7369 6f6e 根据utf8的编码,先看e表示"1110",表示这个字符占3个字节,efbb bf被解析掉,在看3,二进制是"0011",符合ascii码规则,可以查到3f对应字符"<",如此下去,按照utf-8的编码规则解析了文本。
如果按照gbk的编码规则,该是如何解释呢?根据前面的规则,efbb符合gbk解码规则,对应汉语字符"锘",再接着看 bf,在gbk的首字节范围内,而3c明显不在gbk编码的尾字节范围,如此实际上无法解析出正确的编码。
但我们已经发现了,如果统一要求我们书写的代码按照gbk的编码方式存储,将无法出现BOM头。
二、php代码存储的编码方式和代码执行输出的编码的关系
前段提到了代码的存储方式,就是以什么样的编码方式存储,像以utf-8,GBK,UTF-16等等方式,但是代码需要执行相关操作,例如读取和输出操作,这个地方涉及到几个问题是
1、utf8编码存储的代码读取gbk编码的输入,会按照什么样的情况解码?
2、utf8编码存储的代码输出字符串的时候,输出的字符串是什么样的编码?
这两个问题,在实验中发现,如果php脚本是utf8编码存储,那么它输出字符串后,所输出的字符串会是utf8编码,如果php脚本是gbk的编码存储,所输出的字符串会是gbk字符串。这一点,会说明一个问题就是。如果再php脚本中输出一个xml,他和xml申明的encoding=utf8还是gbk没有关系。这个encoding只是告诉调用者按照什么样的编码格式去解码。所以在这个地方要注意脚本存储的编码格式在和xml的encoding不一致的时候,需要做转码的工作。
三、substr在php脚本用使用的问题
substr在php中主要用来截取字符串,如果字符串是英文,一般情况下没有问题,可以数数字符的个数,但是如果是中文,则需要非常小心,首先要判断输入的字符是什么样的编码,如果是gbk编码。汉字都是两个字节,而如果是utf8编码,汉字在3到4个字节。所以判断输入的汉字时候,会非常麻烦,如果必须要判断,可以试试下面步骤
1、先将输入字符转成gbk格式,
2、从开始读取字符串,判断字节是否大于0x7F,如果大于0x7F,则读取两个字节,反正读取一个字节。