【问题标题】:perl Encode::Guess with and without hints - detecting utf8perl Encode::Guess 有和没有提示 - 检测 utf8
【发布时间】:2019-04-08 08:33:14
【问题描述】:

我对 Encode::Guess 感到困惑。假设这是我的 perl 代码:

use strict; 
use warnings;
use 5.18.2;
use Encode;
use Encode::Guess qw/utf8 iso-8859-1/;
use open IO => ':encoding(UTF-8)', ':std';
my $str1 = "1 = educa\x{c3}\x{a7}\x{c3}\x{a3}o";
my $str2 =  "2 = educa\x{e7}\x{e3}o";

say "A: ".&fixEnc($str1);
say "B: ".&fixEnc($str1,'hint');
say "C: ".&fixEnc($str2);
say "D: ".&fixEnc($str2,'hint');
say "";

sub fixEnc() {
    my $data = $_[0];
    my $enc = "";
    if ($_[1]) {
        $enc = guess_encoding($data,qw/utf8 iso-8859-1/);
    } else {
        $enc = guess_encoding($data);
    };
    if (!ref($enc)) {
        return "ERROR: Can't guess: $enc for $data";
    } else {
        my $utf8 = decode($enc->name, $data);
        $utf8 = "encoding guess: ".$enc->name."; result: $utf8";
        return $utf8;
    };
};

它产生:

A1: ERROR: Can't guess: iso-8859-1 or utf8 for 1 = educação
B2: ERROR: Can't guess: utf8 or iso-8859-1 for 1 = educação
C1: encoding guess: iso-8859-1; result: 2 = educação
D1: encoding guess: iso-8859-1; result: 2 = educação

现在,如果我替换 'use Encode::Guess qw/utf8 iso-8859-1/;'通过'使用编码::猜测;'我明白了

A2: encoding guess: utf8; result: 1 = educação
B2: ERROR: Can't guess: iso-8859-1 or utf8 for 1 = educação
C2: ERROR: Can't guess: No appropriate encodings found! for 2 = educação
D2: encoding guess: iso-8859-1; result: 2 = educação

造成这种差异的原因是什么?特别是,为什么我用utf8提示时不会猜到utf8?

编辑:我在下面发布了一个答案。基本上,人们意识到 Guess 使用字符编码并且不会说葡萄牙语! 'educação',虽然不是葡萄牙语,但 Guess 无法区分上面字符串 1 的 正确 latin-1 版本(与说葡萄牙语的人不同)。

【问题讨论】:

标签: perl utf-8 encode utf


【解决方案1】:

我认为这就是正在发生的事情。对于use Encode::Guess qw/utf8 iso-8859-1/;,“提示”没有区别(抱歉不清楚!),所以我们只有

A1/B1: ERROR: Can't guess: iso-8859-1 or utf8 for 1 = educação

和 C1/D1:编码猜测:iso-8859-1;结果:2 = educação

对于 A1/B2,字符串可以是 UTF8 (educação) 或 latin1 (educação)。第二个看起来不正确,但 Encode::Guess 无法分辨 - Guess 使用字符编码并且不会说葡萄牙语!

现在,如果我替换 'use Encode::Guess qw/utf8 iso-8859-1/;'通过'使用编码::猜测;'我明白了

A2: encoding guess: utf8; result: 1 = educação

latin-1 不再是一个选项(它不是默认的一部分),所以结果是 utf8。

B2: ERROR: Can't guess: iso-8859-1 or utf8 for 1 = educação

在 B2 中,随着命中,我们又回到了上述场景,Guess 无法决定。

对于 C2:

C2: ERROR: Can't guess: No appropriate encodings found! for 2 = educação

这是有道理的,因为 latin-1 不是默认值的一部分。终于在 D2 中

D2: encoding guess: iso-8859-1; result: 2 = educação

latin-1 被提示,因此编码被检测到。

【讨论】:

    【解决方案2】:

    很难确定,因为工作中存在一些问题使得检测编码变得困难。

    首先是 iso-8859-1 与 utf8 共享其几乎所有代码点的事实。除非字符串开头有明确的字节顺序标记或 iso-8859-1 中不存在的字符,否则 Encode::Guess 真的只是猜测。

    perldocs 的Encode::Guess caveats 中提到了第二个。 Encode::Guess 使用“试错”算法遍历文本,以消除除提供的一种编码之外的所有编码。自然,编码越相似,模块的准确度就越低。

    第三,当你没有在 use 语句中指定允许的编码类型时,模块会将它与它所能做的一切进行比较。这与试错法以及 utf8 与 iso-8859-1 代码点的重叠相结合,意味着 Encode::Guess 有可能根据传递给该方法的参数得出不同的结论。我想如果你检查两个不同的编码,比如 utf8 和 7bit-jis,你会得到更一致的结果。

    最后,Perl 有more than one implementation of utf8,所以当您没有明确指定“utf8”编码时,它也可能使用不同的实现,这也可能会改变结果。不过,我对 Perl 的内部结构知之甚少,无法确认在这种情况下发生了什么。

    【讨论】:

    • 即使存在 UTF-8 BOM 也不能最终将其与 ISO-8859-1 区分开来。 BOM 是有效的 ISO-8859-1,对应于字符 。
    猜你喜欢
    • 1970-01-01
    • 2016-11-12
    • 2018-08-08
    • 2023-03-15
    • 2016-10-12
    • 2012-08-27
    • 2015-09-19
    • 1970-01-01
    相关资源
    最近更新 更多