Encode :: Guess:guess_encoding在不同的上下文中给出不同的结果

时间:2019-03-08 14:32:06

标签: perl character-encoding

我有以下打开文本文件的子项,并尝试确保其编码为UTF-8,ISO-8859-15或ASCII之一。

我遇到的问题是交互式和非交互式使用中的行为不同。

  • 当我与包含UTF-8行的文件进行交互运行时,按预期,$decoder是一个引用对象,其name返回该行的utf8。

  • 非交互(因为它作为Subversion提交钩子的一部分运行)guess_encoding返回utf8 or iso-8859-15检查行的标量字符串utf8和{{ 1}}用于其他两行。

我不能一辈子,找出行为差异来自何处。如果我强制将iso-8859-15 or utf8的编码说成open,它将毫无疑问地接受每一行作为UTF-8。

问题是我不能假设它接收到的每个文件都是UTF-8,所以我不想强制编码作为变通方法。另一个可能的解决方法是解析标量文本,但这似乎很混乱,尤其是当它在交互式上下文中似乎可以正常工作时。

我已经尝试从外壳程序中覆盖<:encoding(utf8)(由于未设置为非交互方式,因此$LANG变量均未设置),但是交互版本仍然可以正常运行。 / p>

注释为LC_的注释行在注释时以交互和非交互方式返回0。

最终,我们要防止的一件事是在存储库中使用UTF-16或其他宽字符编码(因为我们的某些工具不能很好地使用它):我以为寻找白色-编码列表比查找黑名单要容易得多。

$Encode::Guess::NoUTFAutoGuess

1 个答案:

答案 0 :(得分:1)

无需猜测。对于UTF-8,ISO-8859-1和US-ASCII的特定选项,可以使用Encoding::FixLatinfix_latin。是virtually guaranteed to succeed

也就是说,我认为OP中使用ISO-8859-1是ISO-8859-15的错字。

fix_latin使用的方法在ISO-8859-15中和在ISO-8859-1中一样有效。这只是将_init_byte_map替换为以下内容的问题:

sub _init_byte_map {
    foreach my $i (0x80..0xFF) {
        my $byte = chr($i);
        my $utf8 = Encode::from_to($byte, 'iso-8859-15', 'UTF-8');
        $byte_map->{$byte} = $utf8;
    }
}

或者,如果您愿意假设数据全部是一种编码或另一种编码(而不是混合编码),则还可以使用以下方法:

my $text;
if (!eval {
   $text = decode("UTF-8", $bytes, Encode::FB_CROAK|Encode::LEAVE_SRC);
   1  # No exception
}) {
   $text = decode("ISO-8859-15", $bytes);
}

请记住,US-ASCII是UTF-8和ISO-8859-15的适当子集,因此不需要特殊处理。