【发布时间】:2019-03-08 14:32:05
【问题描述】:
我有以下子程序打开一个文本文件并尝试确保其编码是 UTF-8、ISO-8859-15 或 ASCII 之一。
我遇到的问题是交互式和非交互式使用中的不同行为。
当我以交互方式运行包含 UTF-8 行的文件时,
$decoder正如预期的那样是一个引用对象,其name为该行返回 utf8。非交互方式(因为它作为 subversion 提交挂钩的一部分运行)
guess_encoding为utf8检查行返回值utf8 or iso-8859-15的标量字符串,为其他两行返回iso-8859-15 or utf8.
我一辈子都无法弄清楚行为差异的来源。如果我强制open 的编码为<:encoding(utf8),它将毫无疑问地接受每一行作为 UTF-8。
问题是我不能假设它收到的每个文件都是 UTF-8,所以我不想强制编码作为解决方法。另一种可能的解决方法是解析标量文本,但这看起来很混乱,尤其是当它似乎在交互式上下文中正常工作时。
在 shell 中,我尝试覆盖 $LANG(因为未设置非交互式,也未设置任何 LC_ 变量),但交互式版本仍然可以正常运行。
报告$Encode::Guess::NoUTFAutoGuess 的已注释掉的行在注释时在交互式和非交互式使用中都返回 0。
最终,我们试图阻止的一件事是在我们的存储库中使用 UTF-16 或其他宽字符编码(因为我们的一些工具不能很好地使用它):我认为寻找白色- 编码列表比寻找编码黑名单更容易。
sub checkEncoding
{
my ($file) = @_;
my ($b1, $b2, $b3);
my $encoding = "";
my $retval = 1;
my $line = 0;
say("Checking encoding of $file");
#say($Encode::Guess::NoUTFAutoGuess);
open (GREPFILE, "<", $file);
while (<GREPFILE>) {
chomp($_);
$line++;
my $decoder = Encode::Guess::guess_encoding($_, 'utf8');
say("A: $decoder");
$decoder = Encode::Guess::guess_encoding($_, 'iso-8859-15') unless ref $decoder;
say("B: $decoder");
$decoder = Encode::Guess::guess_encoding($_, 'ascii') unless ref $decoder;
say("C: $decoder");
if (ref $decoder) {
$encoding = $decoder->name;
} else {
say "Mis-identified encoding '$decoder' on line $line: [$_]";
my $z = unpack('H*', $_);
say $z;
$encoding = $decoder;
$retval = 0;
}
last if ($retval == 0);
}
close GREPFILE;
return $retval;
}
【问题讨论】:
-
我以为你应该输入 Encode::Guess 整个数据集(文件)以获得最准确的结果?对我来说,您似乎正在尝试分别猜测每一行的编码。即使是 UTF-8 文件,有些行可能没有字节组合,使它看起来像 UTF-8,所以对于那些行,猜测也会考虑 ASCII 或 ISO-8859-15。
-
我也认为你应该在
open()中使用<:raw。 -
从已知的角度来看,ISO-8859-1=Yes。没有任何字节值或值序列与 ISO-8859-1 不兼容。
-
等等,在一个地方你说
ISO-8859-1,但在其他地方你说-15。-1是错字吗? -
大家好,感谢 cmets - 对整个文件进行更改并给出guess_encoding()。然而,核心问题仍然存在:当以交互方式运行时,
$decoder最终成为引用类型,当通过 SVN 挂钩以非交互方式运行时,$decoder最终成为标量。我想了解为什么会有所不同?