3

考虑以下问题:

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

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

我目前的尝试如下所示:

$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(...)潜艇的启发式/功能?

4

5 回答 5

2

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

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

如果没有这种领域知识,您的问题通常是棘手的。

于 2010-03-31T18:10:37.283 回答
2

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

于 2010-03-31T22:19:05.823 回答
1

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

于 2010-03-31T17:55:33.633 回答
1

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

于 2010-03-31T18:16:17.383 回答
0

简而言之,我选择使用“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
于 2010-12-18T02:55:46.550 回答