【问题标题】:Perl Encode::Guess doesn't know about simple ISO-8859-1/latin1 characters?Perl Encode::Guess 不知道简单的 ISO-8859-1/latin1 字符?
【发布时间】:2016-11-12 07:58:27
【问题描述】:

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

我正在使用带有Encode::Guess 的Perl,我很惊讶它无法处理简单的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

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

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

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

我还在文件句柄上尝试了binmode,但仍然看到错误。

【问题讨论】:

  • 如果文件包含 Latin-1 和 UTF8 的混合(甚至可能是一些 CP1252),那么我建议您尝试Encoding::FixLatin
  • 始终使用use strict; use warnings 'all';!!!如果你有,你的代码会产生 Use of uninitialized value $_ in pattern match (m//) at a.pl line 3.
  • @GrantMcLean:也许你应该说这是你自己的模块?
  • 不好意思(缺少“qw”)-我已经更新了问题。
  • @DavidLjungMadison:下面我的解决方案还没有解决什么问题?

标签: perl encoding utf-8 iso-8859-1


【解决方案1】:

这一行

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

应该是

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

【讨论】:

  • 感谢您发现这个令人尴尬的错字 - 我已经更新了问题。
【解决方案2】:

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

在模式匹配中使用未初始化的值 $_ (m//)

你真的应该告诉我们的

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

这应该适合你

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

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

【讨论】:

  • FixLatin 很有意义,尽管我不想安装新的库来解决这个问题。当我使用binmode :utf8 逐行读取文件时,guess_encoding 并不完全有效。在我的系统上,perl Encode 无法猜测 é (0xc3 0xa9) 的 utf-8 编码实际上是 utf-8 还是 é 的 latin1。我想这是猜测编码的问题之一,可能是 fix_latin 真正有用的地方。 guess_encoding 返回 utf-8 和 latin1,现在我想我可以在这些情况下猜测 utf-8 并希望最好。
猜你喜欢
  • 1970-01-01
  • 2013-01-19
  • 1970-01-01
  • 2021-11-10
  • 2023-03-27
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 2015-10-27
相关资源
最近更新 更多