确保字符串为UTF-8编码

6

我的应用程序读取一个csv文件并将其内容显示给用户。但是有一个编码问题。

我有两个csv文件example1.csvexample2.csv。我都在记事本++中打开了它们,其中example1显示为ANSI编码,example2显示为UTF-8无BOM。

首先,我尝试使用mb_detect_encoding函数检测编码,但它在两种情况下都显示UTF-8,这是不正确的。

其次,我尝试使用utf8_encode将文件内容转换为UTF-8。对于ANSI文件,它可以正常工作。但是对于UTF-8无BOM文件,似乎又被重新编码回ANSI。它显示Ã而不是德语ß,其他特殊字符也是一样。

我想确保在显示或处理内容之前始终以UTF-8格式呈现它们。那么我做错了什么吗?


这是我如何使用mb_detect_encoding函数:

$file_content = file_get_contents($_FILES['file']['tmp_name']);

die(var_dump( mb_detect_encoding($file_content))); 

并且它在这两个例子中都打印出了UTF-8。


1
ASCII是ANSI的子集,也是UTF-8的子集,因此对于某些实际上是ASCII的特定文件,“它是ANSI”和“它是UTF-8”都可能是正确的。你的示例1是这种类型的文件吗? - Jon
@Jon mb_detect_encoding 对于这两个文件都返回 UTF-8。例如1在记事本++中显示为 ANSI。所以是那种类型的文件。 - DarkLeafyGreen
请展示使用mb_detect_encoding()函数的代码,以展示您的具体用法。 - goat
我需要帮助修复破损的UTF8编码。 - giorgio79
2个回答

10

介绍:另一个不便之真相

无法以100%的准确度和/或信心检测未知文本的编码。

实际上,可能会出现各种可能结果的情况:您可以非常确定UTF-8中的多语言文本将被正确地检测为这样,而无法检测到ISO-8859编码系列中哪个对应于某些文本--除非您愿意进行统计分析,否则甚至不可能做出有根据的猜测!

我们有什么可以使用的工具?

解决了以上问题后,让我们看看你能做些什么。首先,除非你带来自定义工具,否则你受限于mb_detect_encoding所能为你提供的内容。不幸的是,那不算太多。姊妹函数mb_detect_order的文档说明如下:

mbstring目前实现了以下编码检测过滤器。如果以下编码存在无效字节序列,则编码检测将失败:UTF-8、UTF-7、ASCII、EUC-JP、SJIS、eucJP-win、SJIS-win、JIS、ISO-2022-JP。对于ISO-8859-X,mbstring总是检测为ISO-8859-X。对于UTF-16、UTF-32、UCS2和UCS4,编码检测将始终失败。因此,除了日语编码外,您基本上可以区分UTF-8、UTF-7和ASCII。您无法检测ISO-8859-X,因为任何文本都将被“识别”为这些编码之一(即您将具有100%的误报率-不好),而包括UTF-16在内的另一组编码根本不受支持。

不幸的是,坏消息并没有结束。 编码顺序也很重要! 由于使用UTF-7或ASCII编码的文本也是有效的UTF-8,将UTF-8放在候选列表的最前面将确保您只会得到这种结果--因此必须尽一切可能避免。

由于默认检测顺序取决于php.ini setting,您绝不能依赖它,并通过设置自己的检测顺序进入已知状态:

mb_detect_order('ASCII, UTF-8'); // I left UTF-7 out, but who cares?

所以你至少可以判断你的文本是ASCII还是UTF-8,对吗?嗯,并不是。除非你明确要求在说“UTF-8”时,“你真的是指它”。
$valid_utf8 = "\xC2\xA2";
$invalid_utf8 = "\xC2\x00";

mb_detect_order('UTF-8');
echo mb_detect_encoding($valid_utf8);   // "utf-8": correct
echo mb_detect_encoding($invalid_utf8); // "utf-8": WTF?!?!?!

上述问题在于,除非您为$strict参数传递true,否则检测UTF-8会有点过于乐观。
那么,您实际上可以用这个东西做什么呢?
这是最好的方法——正确地检测编码(勉强使用复数形式)。
$valid_utf8 = "\xC2\xA2";
$invalid_utf8 = "\xC2\x00";
$ascii = "hello world";

mb_detect_order('ASCII, UTF-8');
echo mb_detect_encoding($valid_utf8, mb_detect_order(), true);   // OK: "utf-8"
echo mb_detect_encoding($invalid_utf8, mb_detect_order(), true); // OK: false
echo mb_detect_encoding($ascii, mb_detect_order(), true);        // OK: "ascii"

如何处理无效的UTF-8文本?

除非你已经掌握了该文本的其他信息,否则很遗憾没有任何方法

好吧,这并不完全正确。实际上有一些事情可以做:

  1. 查看文本开头是否有BOM。可能没有,即使有,从数学上讲,你也可能将单字节编码误认为是Unicode,但值得一试。
  2. 查看它是否是UTF-16的一种变体。如果偶数位字节的大多数具有相同的值,则很可能是UTF-16 LE。如果奇数位字节的大多数都是相同的值,则很可能是UTF-16 BE。不幸的是,在这两种情况下,你永远无法确定。
  3. 假设文本采用ISO-8859-X编码,并根据对应于此编码的脚本的已知属性进行统计分析,以查看结果是否接近预期。如果对于某些编码而言足够接近,而对于其他编码而言则差距很大,那么你可以进行有根据的猜测。

-1

要检查utf8,请执行以下操作

if (mb_check_encoding(file_get_contents($file), 'UTF-8')) {
    // yup, all UTF-8
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接