PHP处理文件BOM,编码转换与Emacs编码相关设置,以及utf-8空格问题(194 160)

Saturday, April 14, 2018

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);

(完)

EmacsPHP

json_encode()与json_decode()特殊情况汇总

由last_insert_id()引发的错误