Perl Encode::Guess 不知道简单的 ISO-8859-1/latin1 字符?

Perl Encode::Guess doesn't know about simple ISO-8859-1/latin1 characters?

我正在尝试找出许多输入字符串的编码,有些是 UTF-8,有些是 ISO-8859-1。不幸的是。

我将 Perl 与 Encode::Guess 一起使用,我很惊讶地发现它无法处理简单的 Latin1 编码。我正在使用 Encode::Guess 文档中的解码示例。

我一直在读取文件,但我也可以对字符串进行硬编码以获得相同的错误:

use Encode::Guess;

my $data = "The name \xc5sa is Swedish\n";
my $enc = guess_encoding($data,qw/latin1 utf8 ascii/);
ref($enc) or die "Can't guess: $enc\nFOR: $data";

然后我得到:

Can't guess: No appropriate encodings found!
FOR: The name �sa is Swedish

尽管在我的编辑器中,我看到第一个字符是 Aring 的“Åsa”。

Perl 是否预先确定了编码,因为它是一个字符串而不是一组打包的二进制数据,这就是破坏它的原因?

我在读取文件时尝试了 use open ":encoding(Latin1)";,错误消失了,但它猜测编码是 UTF-8。无论如何,该文件逐行混合了 UTF-8 和 Latin1,所以我想 运行 Encode::Guess 每行。

我也尝试 binmode 文件句柄,但仍然看到错误。

这一行

my $enc = guess_encoding($data,/latin1 utf8 ascii/);

应该是

my $enc = guess_encoding($data,qw/latin1 utf8 ascii/);
                               ^^

你的程序有问题。参数 /latin1 utf8 ascii/ 正在尝试将正则表达式模式应用于(未定义的)变量 $_。您会看到一条警告消息

Use of uninitialized value $_ in pattern match (m//)

你真的应该告诉我们

请注意,use open ":encoding(Latin1)" 与在您打开文件句柄时对每个文件句柄应用 binmode $fh, ":encoding(Latin1)" 相同,并且会在您读取数据时尝试将数据解码为 Latin1。结果将是一个字符串,该字符串对文件中的 Latin1 字符使用 Perl 的内部编码。如果其中一些是 UTF-8,那将是灾难性的。 A 环字符的 UTF-8 编码是两个字节 C3 85,它被视为 Latin1,是一个波浪号后跟一个非法字符

这应该适合你

use strict;
use warnings 'all';
use feature 'say';

use Encode::Guess;

for my $data (
        "The name \xC5sa is Swedish\n",
        "The name \N{U+00C5}sa is Swedish\n" ) {

    my $enc = guess_encoding($data, qw/ latin1 utf8 ascii /);
    ref($enc) or die "Can't guess: $enc\nFOR: $data";

    say $enc->name;
}

输出

iso-8859-1
utf8



更新

我强烈推荐 Grant McLean 的 Encoding::FixLatin 模块,它可以满足您的所有需求。它还将涵盖在一行中使用两种编码的情况

该程序处理一个使用 Latin1 编码的字符串和另一个使用 UTF-8 编码的字符串。使用 fix_latin

处理后,两者都可以毫无问题地打印出来
use strict;
use warnings 'all';
use feature 'say';

use open qw/ :std :encoding(UTF-8) /;

use Encoding::FixLatin 'fix_latin';

for my $data (
        "The name \xC5sa is Swedish\n",
        "And so is Asbj\N{U+00F6}rn\n" ) {

    my $utf8 = fix_latin($data);
    print $utf8;
}

输出

The name Åsa is Swedish
And so is Asbjörn

最好使用此技术一次性读取和处理整个文件。除非文件很大并且会导致内存问题,否则逐行读取文件没有意义