我有一个内容为UTF-8编码的CSV。但是,各种应用程序和系统错误地将CSV的编码检测为Windows-1252
,它会破坏文件中的所有特殊字符(例如Umlauts)。
我可以看到Sublime Text(在Windows上)例如在第一次打开文件时也自动检测到错误的Windows-1252
编码,显示特殊字符应该是的乱码文本。
当我选择重新打开编码»UTF-8时,一切看起来都不错,正如预期的那样。
现在,为了找到错误的来源,我认为这可能有助于弄清楚,为什么这些应用程序不会自动检测到正确的编码。例如,可能存在一个带有错误编码的杂散字符。
有问题的CSV实际上是Magento 2安装的自动生成的产品导出。最近字符编码打破了,我正在试图弄清楚发生了什么 - 因此我调查了为什么这个出口被检测为Windows-1252
。
是否有任何可靠的方法来确定为什么像Sublime Text这样的应用程序的自动检测会采用错误的字符编码?
这就是我最后所做的,找出为什么文件没有被检测为UTF-8,即找到没有用UTF-8编码的字符。由于PHP更容易使用,我决定只使用以下脚本,使用非常方便的neitanod/forceutf8库强制将非UTF-8的任何东西转换为UTF-8。
$before = file_get_contents('export.csv');
$after = \ForceUTF8\Encoding::toUTF8($before);
file_put_contents('export.fixed.csv', $after);
然后我使用Beyond Compare之类的文件比较工具来比较两个生成的CSV,以便更容易地看到哪些字符最初没有用UTF-8编码。
这反过来告诉我,只有一个特定的出口栏受到影响。经过进一步调查后,我发现该列的内容是使用以下preg_replace
在PHP中处理的:
$value = preg_replace('/([^\pL0-9 -])+/', '', $value);
在正则表达式中使用\p
有一个未知的副作用:所有特殊字符都转换为另一种编码。对此的快速解决方案是在正则表达式上使用u
标志(请参阅regex pattern modifiers reference)。这迫使此preg_replace
的结果编码为UTF-8。另见this answer。