php - 确保字符串是 UTF-8 编码的

标签 php csv utf-8

在我的应用程序中,我读取了一个 csv 文件并向用户显示内容。但是编码有问题。

我有两个 csv 文件 example1.csvexample2.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 的文本?

除非您有关于该文本的带外信息,否则很遗憾没有

好吧,这不完全正确。您可以在实践中做一些事情:

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

关于php - 确保字符串是 UTF-8 编码的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15176581/

相关文章:

Python:如何删除 CSV 文件中单独出现的句点?

java - 将 UTF-8 字节数组编码和解码为字符串

php - ini_set ('mbstring.internal_encoding' ,'UTF-8' )

php - 将 jQuery 的可排序列表插入 MySql

php - 每 x 分钟重复将图像文件从一台服务器保存到另一台服务器

php - 插入数据库的字符串不完整

python - 使用 pandas.read_csv 读取以空格为千位分隔符的 CSV 文件

java - 使用 StringBuffer 值将列添加到 CSV 文件 (Java)

c - 从 UTF8 读取文件

当文件名中包含 +(加号)时,PHP file_get_contents() 不起作用