【问题标题】:___ encoding to UTF-8 - is there an end-all solution?___ 编码为 UTF-8 - 是否有最终解决方案?
【发布时间】:2010-06-11 21:01:56
【问题描述】:

我浏览过网络,浏览过 SO,浏览过 PHP 文档等等。

没有标准解决方案似乎是一个荒谬的问题。如果你得到一个未知的字符集,并且它有奇怪的字符(比如英文引号),有没有一种标准的方法可以将它们转换为 UTF-8?

我见过很多混乱的解决方案,使用过多的函数和检查,但没有一个肯定会起作用。

有没有人提出自己的功能或始终有效的解决方案?


编辑

许多人回答说“它无法解决”或类似的东西。我现在明白了,但除了utf8_encode 之外,没有人给出任何有效的解决方案,这是非常有限的。有什么方法可以解决这个问题? 最好的方法是什么?

【问题讨论】:

标签: php utf-8 character-encoding special-characters iso-8859-1


【解决方案1】:

没有。应该始终知道字符串的字符集。使用嗅探函数猜测字符集是不可靠的(尽管在大多数情况下,在西方世界,它通常是 ISO-8859-1 和 UTF-8 之间的混淆)。

但是为什么你必须处理未知的字符集呢?对此没有通用的解决方案,因为首先不应该存在通用问题。每个网页和数据源都可以而且应该有一个字符集定义,如果没有,应该请求该资源的管理员添加一个。

(听起来不像是个聪明人,但处理这个问题的唯一方法。)

【讨论】:

  • RSS 提要是为什么需要这样做的一个常见示例。人们在他们的计算机上使用不同的字符集从各种不同的编辑器上传文件或复制和粘贴。
  • @Kerry 对于 RSS 提要来说确实如此,但在每个提要的背后一个应该做他们的工作的管理员。关于用户复制+粘贴:要点。这是一个真实的场景,有时无法定义编码。
  • 将文本复制粘贴到表单中不是问题,因为浏览器无论如何都不知道如何显示文本 - 当它放在剪贴板上时会转换为 Unicode,而浏览器知道将文本转换为它应该发送的任何编码。由于 XML 序言,RSS 提要也不应该成为问题 - 但如果缺少它,那么它可能也会在许多其他地方失败,除非编码是 UTF-8 或 UTF-16。
  • @Michael 是的,我对剪贴板也有同样的想法。然而,可以想象,有时事情会出现乱码,内容取自错误编码的网站,外部以不同的编码嵌入到网站中......不过,复制+粘贴可能不像我最初想象的那样严重。
  • 我不能依赖其他 RSS 提要的管理员来很好地维护他们的提要,这样做是一个很大的错误。我不知道剪贴板,这很好,但我仍然想要一个最终的解决方案或某种解决方案
【解决方案2】:

你看到这么多复杂的解决方案的原因是因为从定义上看它是不可解决的。对文本字符串进行编码的过程是不确定的。 可以构建产生相同字节流的文本和编码的不同组合。因此,从严格的逻辑上讲,不可能从一个字节流中确定编码、字符集和文本。

实际上,使用启发式方法可以获得“足够接近”的结果,因为您会在野外遇到一组有限的编码,并且通过足够大的样本,程序可以确定最有可能的编码。结果是否足够好取决于应用程序。

我确实想对用户生成数据的问题发表评论。从网页发布的所有数据都具有已知的编码(POST 带有开发人员为页面定义的编码)。如果用户将文本粘贴到表单域中,浏览器将根据源数据的编码(操作系统已知)和页面编码来解释文本,并在必要时对其进行转码。检测服务器上的编码为时已晚——因为浏览器可能已经根据假定的编码修改了字节流。

例如,如果我在德语键盘上键入字母 Ä 并将其发布到 UTF-8 编码的页面上,则会有 2 个字节 (xC3 x84) 发送到服务器。这是表示字母 C 和 d 的有效 EBCDIC 字符串。这也是一个有效的 ANSI 字符串,表示 2 个字符 Ã 和 „。但是,无论我如何尝试,都不可能将 ANSI 编码的字符串粘贴到浏览器表单中并期望它被解释为 UTF-8 - 因为操作系统知道我正在粘贴 ANSI(我复制了我在其中创建了一个 ANSI 编码的文本文件的 Textpad 中的文本)并将其转码为 UTF-8,从而生成字节流 xC3 x83 xE2 x80 x9E。

我的观点是,如果用户设法发布垃圾,可以说是因为它在粘贴到浏览器表单时已经是垃圾,因为客户端没有正确支持字符集、编码, 任何。 因为字符编码是不确定的,所以你不能指望有一种简单的方法可以从这种情况中发现。

不幸的是,对于上传的文件,问题仍然存在。我看到的唯一可靠的解决方案是向用户显示文件的一部分并询问它是否被正确解释,然后循环通过一堆不同的编码,直到出现这种情况。

或者我们可以开发一种启发式方法来查看某些字符在各种语言中的出现情况。假设我上传了包含两个字节 xC3 x84 的文本文件。没有其他信息 - 文件中只有两个字节。这种方法可以发现字母Ä在德语文本中相当常见,但字母Ã和„一起在任何语言中都不常见,从而确定我的文件的编码确实是UTF-8。这种粗略是这种启发式方法必须处理的复杂程度,它可以使用的统计和语言事实越多,其结果就越可靠。

【讨论】:

  • 感谢你的这篇文章——我已经更新了我的问题,我觉得你可能有最好的答案。你让我知道它是如何工作的,是否有任何类型的脚本或函数可以处理?
  • 没有通用的解决方案。这取决于你的情况。如果您可以通过限制编码或语言的数量以某种形式减少问题,例如,可能会有。例如看这篇文章。 stackoverflow.com/questions/805418/… 每个建议的解决方案似乎都有局限性。
  • 看来我将不得不进行某种查找并替换超出范围的任何内容。我将其限制为英语。
【解决方案3】:

Pekka 对不可靠性的看法是正确的,但如果您需要一个解决方案并愿意承担风险,并且您有可用的 mbstring 库,那么这个 sn-p 应该可以工作:

function forceToUtf8($string) {
    if (!mb_check_encoding($string)) {
        return false;
    }
    return mb_convert_encoding($string, 'UTF-8', mb_detect_encoding($string));
} 

【讨论】:

  • 我认为这对许多人来说可能是一个很好的解决方案,虽然将 return false 更改为 return $string,但对我不起作用
  • mb_detect_encoding 只能识别一小部分编码 - UTF-8、UTF-7、ASCII 和一堆日语编码。它不适用于大多数编码。
【解决方案4】:

如果我没记错的话,有一个叫做 utf8encode 的东西......它工作得很好,除非你已经在 utf8 中

http://php.net/manual/en/function.utf8-encode.php

【讨论】:

  • 是的,我试过了,如果失败也会返回一个空字符串
  • 根据手册,utf8encode 仅适用于 ISO-8859-1 字符串,因此对于未知编码的情况并没有真正的帮助。
猜你喜欢
  • 2016-08-20
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 2020-12-09
  • 1970-01-01
  • 2012-11-07
  • 2018-11-05
  • 2021-05-13
相关资源
最近更新 更多