PHP处理文件BOM,编码转换与Emacs编码相关设置,以及utf-8空格问题(194 160)
PHP处理文件BOM
当涉及到文件处理的时候,不可避免的要接触windows的记事本。
当记事本另存为UTF-8编码的时候会带上BOM头,在一些文本编辑器下会显示为UTF-8 with BOM
。
用Emacs(hexl-mode),vi(%!xxd),shell命令等都可以查看文件的16进制内容:
cat a.txt | xxd
之后你会发现UTF-8编码的BOM头其实就是0xEF0xBB0xBF,知道内容后去除的办法就很多了:
$str = file_get_contents("a.txt");
// 方法1
$str = ltrim($str, "\xEF\xBB\xBF");
// 方法2
$str = str_replace("\xEF\xBB\xBF", '', $str);
// 等等
参考链接:how-to-remove-multiple-utf-8-bom-sequences-before-doctype
PHP编码转换
php有个函数是mb_detect_encoding,这个函数用来检验第一个参数字符串的编码。经常看到有代码是这样写的:
echo mb_detect_encoding($str, array('UTF-8', 'GB2312', 'GBK'));
虽然没有报错,但是个人觉得这样写有点问题,因为手册上描述的第二个参数是字符编码列表,而上述代码中的GB2312,GBK这都是字符集,而字符编码是字符集的实现方案。当我们这样使用这个函数,或者别人看到的时候可能第一感觉是从第二个参数里找到符合字符串的字符编码,而这样调用返回的字符编码可能是CP936,EUC-CN等,非常容易造成困惑。所以当我们使用这个函数的时候可以这样写:
echo mb_detect_encoding($str, array('UTF-8', 'EUC-CN', 'CP936'));
字符串转码,php有两个函数,一个是iconv,一个是mb_convert_encoding。
echo iconv("UTF-8", "ISO-8859-1//IGNORE", $text);
这里的IGNORE很常用,如果某个字符不能被目标字符集表示的时候,会忽略,否则会有notice并且返回false。 mb_convert_encoding基本类似,但是这两个函数仍然建议不要使用字符集做参数,很容易产生困惑。而且官方文档的示例也没有这样使用的情况。
Emacs编码相关说明
Emacs默认的Mode line长这样:
-UU-:----F1 a.log All (3,0) ......
第一个U代表键盘输入编码,默认是UTF-8,可以使用set-keyboard-coding-system
设置;
第二个U代表文本终端使用的编码,默认也是UTF-8,使用set-terminal-coding-system
设置;
这两个使用Emacs至今没设置过,通常不会出问题。
两个U后面的-
,代表的当前文件的编码,默认进来的时候显示为-
,当我们设置过文件编码,或使用revert-buffer-with-coding-system
函数设置过文件编码之后,会显示为相应编码的简写,例如-UUU:
,即当前缓冲区的编码为UTF-8。
buffer的编码并不等于文件的编码,当我们设置了buffer编码,只是影响当前可视区域的显示,不会影响文件的保存。
设置保存文件的编码用set-buffer-file-coding-system
函数。在linux下我们可以用file
命令来查看文件相关信息:
shell: file a.log
// output
a.log: UTF-8 Unicode text, with CRLF, LF line terminators
a.log: ISO-8859 text, with CRLF, LF line terminators
上面的输出中,换行符关键字对应关系为:
CRLF -> \r\n
LF -> \n
CR -> \r
Mode line中的冒号位置就代表了换行符的格式。当然换行符也是和文件编码有关的,例如,文件编码为UTF-8,但是我们的换行符为 \r\n,那么你看到的可能是^M
。
这块有些系统也会显示为(Unix或者:
),代表 \n,当我们打开Windows上的文件时候,换行符号为 \r\n,那么这个位置会显示为反斜杠 \ 或者 (DOS);同理打开Mac上的文件,换行符为 \r,这时候会显示为斜线 / 或者 (Mac)。
当前编码的详细信息可以通过调用describe-current-coding-system
函数进行查看。
update 2018.9.10
碰到utf-8空格的问题已经两次了,今天是这样的,在导入数据的时候,少了两条,发现uid是0,查看源文件,发现id旁边有空格,用trim处理未果,strlen查看空格长度是2,ascii码分别是194和160。
处理方案:
$converted = trim($converted, chr(0xC2).chr(0xA0));
// 或者
$converted = str_replace(chr(0xC2).chr(0xA0), '', $converted);
(完)
- 本文作者:吴泽辉
- 本文链接:https://mutex.top/posts/e53f8c7c/
- 发表日期:2018年4月14日
- 版权声明:本文章为原创,采用《知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议》进行许可