【问题标题】:Forcing a mixed ISO-8859-1 and UTF-8 multi-line string into UTF-8 in Perl在 Perl 中将混合的 ISO-8859-1 和 UTF-8 多行字符串强制转换为 UTF-8
【发布时间】:2011-02-03 01:18:07
【问题描述】:

考虑以下问题:

多行字符串$junk 包含一些以 UTF-8 编码的行和一些以 ISO-8859-1 编码的行。我不知道先验哪些行在哪个编码中,所以需要启发式。

我想将 $junk 转换为纯 UTF-8,并对 ISO-8859-1 行进行适当的重新编码。此外,如果处理过程中出现错误,我想提供“尽力而为的结果”,而不是抛出错误。

我目前的尝试是这样的:

$junk = force_utf8($junk);

sub force_utf8 {
  my $input = shift;
  my $output = '';
  foreach my $line (split(/\n/, $input)) {
    if (utf8::valid($line)) {
      utf8::decode($line);
    }
    $output .= "$line\n";
  }
  return $output;
}

显然,转换永远不会完美,因为我们缺乏有关每行原始编码的信息。但这是我们能得到的“尽力而为的结果”吗?

您将如何改进force_utf8(...) sub 的启发式/功能?

【问题讨论】:

  • 您不断要求人们对您的代码发表评论,但您没有听他们在说什么。如果你的整个策略是错误的,那么对代码的注释是没有用的。
  • mpeters:我知道这种方法的局限性,因此需要启发式方法——这些东西是可以理解的。我的问题更像是“我知道这不是最佳的,但鉴于这些假设,这是我们能做的最好的吗”?到目前为止,这个问题仍然悬而未决。
  • 这里是对代码的一个注释:不要使用&调用子程序。 force_utf8($junk) 就够了。

标签: perl unicode utf-8 character-encoding text-processing


【解决方案1】:

仅通过查看一个字符,就很难判断它是 ISO-8859-1 还是 UTF-8 编码。问题是两者都是 8 位编码,因此仅查看 MSb 是不够的。那么,对于每一行,我都会假设它是 UTF-8 对行进行转码。当发现无效的 UTF-8 编码时,假设该行确实是 ISO-8859-1,请重新转码该行。这种启发式的问题在于,您可能会转码 ISO-8859-1 行,而这些行也是格式良好的 UTF-8 行;但是,如果没有关于 $junk 的外部信息,则无法判断哪个是合适的。

【讨论】:

  • UTF-8 不是 8 位编码。它以 8 位(“低”或“7 位”ASCII)表示常用的西方字符,但如果需要,将使用多字节字符。
  • UTF-8 是一种 8 位编码,也 100% 兼容 7 位 ASCII。它是否对给定字符使用所有 8 位都与该点正交。
  • 不,它不是 8 位编码。虽然某些 UTF-8 字符串可能仅包含使用 8 位的字符,但字符串中任何给定的 UTF-8 字符的大小最多可达四个字节(32 位)。请参阅 en.wikipedia.org/wiki/UTF-8 或 tools.ietf.org/html/rfc3629。
  • 我明白你的意思;我仍然认为启发式方法适用于所有密集型目的。
  • 适用于所有意图和目的,例如“无论您的意图或目的是什么,这种启发式都应该有效”。
【解决方案2】:

您也许可以使用一些领域知识来解决它。例如,é 不是 ISO-8859-1 中可能的字符组合;它更有可能是 UTF-8 é。

如果您的输入仅限于有限的字符池,您还可以使用启发式算法,例如假设 Ã 永远不会出现在您的输入流中。

如果没有这种领域知识,您的问题通常是难以解决的。

【讨论】:

  • 该代码将处理多种语言的输入,因此很遗憾不能枚举特定的翻译。
【解决方案3】:

看看this的文章。 UTF-8 已优化为以 8 位表示西方语言字符,但不限于每个字符 8 位。多字节字符使用常见的位模式来指示它们是否是多字节的,以及该字符使用了多少字节。如果您可以安全地假设您的字符串中只有两种编码,那么其余的应该很简单。

【讨论】:

    【解决方案4】:

    除了我会先尝试使用Encode::Guess之外,我没有任何有用的建议。

    【讨论】:

      【解决方案5】:

      简而言之,我选择使用“file -bi”和“iconv -f ISO-8859-1 -t UTF-8”来解决我的问题。

      我最近在尝试规范文件名的编码时遇到了类似的问题。我混合了 ISO-8859-1、UTF-8 和 ASCII。当我意识到在处理文件时,我添加了由于目录名称具有一种与文件编码不同的编码而导致的复杂性。

      我最初尝试使用 Perl,但它无法正确区分 UTF-8 和 ISO-8859-1,导致 UTF-8 出现乱码。

      在我的情况下,这是对合理文件数的一次性转换,因此我选择了一种我知道并且对我来说没有错误的慢速方法(主要是因为每行只使用 1-2 个不相邻的字符特殊的 ISO-8859-1 代码)

      选项 #1 将 ISO-8859-1 转换为 UTF-8

      猫混合文本.txt | 我读的时候 type=${"$(echo "$i" | 文件 -bi -)"#*=} 如果 [[ $type == 'iso-8859-1' ]];然后 回声 "$i" | iconv -f ISO-8859-1 -t UTF-8 别的 回声“$ i” 菲 完成 > utf8_text.txt

      选项 #2 将 ISO-8859-1 转换为 ASCII

      猫混合文本.txt | 我读的时候 type=${"$(echo "$i" | 文件 -bi -)"#*=} 如果 [[ $type == 'iso-8859-1' ]];然后 回声 "$i" | iconv -f ISO-8859-1 -t ASCII//TRANSLIT 别的 回声“$ i” 菲 完成 > utf8_text.txt

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-29
        • 2014-07-04
        • 2020-01-25
        • 1970-01-01
        • 2013-01-05
        • 2016-07-29
        • 1970-01-01
        相关资源
        最近更新 更多