在我的应用程序中,我读取了一个 csv 文件并向用户显示内容。但是编码有问题。
我有两个 csv 文件 example1.csv 和 example2.csv。我都在 notepad++ 中打开,它显示 example1 的 ANSI 编码和 example2 的不带 BOM 的 UTF-8。
首先,我尝试了 mb_detect_encoding功能来检测编码,但它在两种情况下都显示 UTF-8,这是不正确的。
其次,我尝试使用 utf8_encode 将文件内容转换为 UTF-8 .这适用于 ANSI 文件。但是对于没有 BOM 文件的 UTF-8,它似乎被编码回 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。
最佳答案
进入:另一个难以忽视的真相
不可能以 100% 的准确度和/或置信度检测未知文本的编码。
在实践中,可能会出现各种可能的结果:您可以非常确定 UTF-8 中的多语言文本将被正确检测到,而完全不可能检测到 ISO 系列中的哪一个-8859 编码对应于某些文本——除非您愿意进行统计分析,否则甚至不可能做出有根据的猜测!
我们必须使用什么?
有了这个,让我们看看您可以做什么。首先,除非您将自定义工具带入战斗,否则您会受到 mb_detect_encoding
可以为您做的事情的限制。不幸的是,这还不是很多。姊妹函数的文档mb_detect_order
状态:
mbstring currently implements the following encoding detection filters. If there is an invalid byte sequence for the following encodings, encoding detection will fail.
UTF-8, UTF-7, ASCII, EUC-JP,SJIS, eucJP-win, SJIS-win, JIS, ISO-2022-JP.
For ISO-8859-X, mbstring always detects as ISO-8859-X.
For UTF-16, UTF-32, UCS2 and UCS4, encoding detection will fail always.
所以,抛开日文编码,你基本上可以区分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 的文本?
除非您有关于该文本的带外信息,否则很遗憾没有。
好吧,这不完全正确。您可以在实践中做一些事情:
- 查看文本开头是否有 BOM。可能不会有,即使在数学上有,您也可能会将单字节编码误认为是 Unicode,但值得一试。
- 看看它是不是 UTF-16 的风格。如果大部分偶数字节具有相同的值,那么您可能正在查看 UTF-16 LE。如果大多数奇数字节发生这种情况,您可能正在查看 UTF-16 BE。不幸的是,在这两种情况下您都无法确定。
- 假设文本采用 ISO-8859-X 格式,并根据与此编码对应的脚本的已知属性进行统计分析,以查看结果是否接近您的预期。如果它对于此类中的某些编码足够接近而对于其他编码则足够远,您可以做出有根据的猜测。
关于php - 确保字符串是 UTF-8 编码的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15176581/