【问题标题】:Proper handing of UTF-8 in Perl在 Perl 中正确处理 UTF-8
【发布时间】:2012-08-01 07:07:07
【问题描述】:

我收到了一个(可能)以 Latin-1 (ISO 8859-1) 编码的文件,并且需要对它进行一些转换和数据挖掘。输出应该是 UTF-8 格式,我已经尝试了所有关于 Perl 编码转换的方法,但没有一个产生任何可用的输出。

我知道use utf8; 一开始就什么都不做。我尝试了Encode 包,看起来很有希望:

open FILE, '<', $ARGV[0] or die $!;

my %tmp = ();
my $last_num = 0;

while (<FILE>) {
    $_ = decode('ISO-8859-1', encode('UTF-8', $_));

    chomp;
    next unless length;
    process($_);
}

我尝试了我能想到的任何组合,还加入了binmode(STDOUT, ":utf8");open FILE, '&lt;:encoding(ISO-8859-1)', $ARGV[0] or die $!; 等等。结果要么是混乱的变音符号,要么是像\xC3 is not a valid UTF-8 character 这样的错误消息,甚至是混合文本(有些是UTF-8,有些是Latin-1)。

我想要的只是一种简单的方法来读取 Latin-1 文本文件并通过 print 在控制台上生成 UTF-8 输出。在 Perl 中是否有任何简单的方法可以做到这一点?

【问题讨论】:

  • Perl 不知道,如何正常使用 utf :(

标签: perl utf-8 character-encoding latin1


【解决方案1】:

也许是:

$_ = encode('utf-8', decode('ISO-8859-1', $_));

数据是gb2312编码,所以可以转成utf-8:

#!/usr/bin/env perl

use Encode qw(encode decode);

while (<DATA>) {
    $_ = encode('utf-8', decode('gb2312', $_));
    print;
}

__DATA__
Â׶ذÂÔË»á

【讨论】:

    【解决方案2】:

    参见Perl encoding introductionUnicode cookbook

    • piconv 最简单:

      $ piconv -f Latin1 -t UTF-8 < input.file > output.file
      
    • 简单,带有编码层:

      use autodie qw(:all);
      open my $input, '<:encoding(Latin1)', $ARGV[0];
      binmode STDOUT, ':encoding(UTF-8)';
      
    • 适度,手动解码/编码:

      use Encode qw(decode encode);
      use autodie qw(:all);
      
      open my $input, '<:raw', $ARGV[0];
      binmode STDOUT, ':raw';
      while (my $raw = <$input>) {
          my $line = decode 'Latin1', $raw, Encode::FB_CROAK | Encode::LEAVE_SRC;
          my $result = process($line);
          print {STDOUT} encode 'UTF-8', $result, Encode::FB_CROAK | Encode::LEAVE_SRC;
      }
      

    【讨论】:

    • 使用 daxim 方法的唯一问题是,如果文件实际上不是 Latin1 - 无论您不幸做什么,混合编码的文件都是一场噩梦。跨度>
    • @RichardHuxton 是否有机会处理这些问题?我怀疑我收到的一些数据是混合编码的。
    • 有 Encode::Guess,但恐怕在不提前知道内容是什么的情况下,几乎不可能区分许多 8 位字符集。例如 8859-15 具有欧元符号,因此具有大量代码点 0xA4 的财务信息可能是它而不是 8859-1。同样,一些威尔士口音字符也在 8859-14 中。虽然不知道文字是什么意思,但这是非常艰苦的工作。这还没有提到人们从 Word 中剪切+粘贴的地方出现的 Microsoft-Word“智能引号”。
    • 如果您要自己解码,最好确保您正在读取原始字节流。在这种情况下,您将默认解码保留给读取的文件决定执行的任何操作,这可能会受到远处的影响。输出也是如此。你必须确保在 STDOUT 上没有设置任何东西来编码你给它的东西。
    【解决方案3】:
    $_ = decode('ISO-8859-1', encode('UTF-8', $_));
    

    这条线有两个问题。首先,您将输入编码为 UTF-8,然后从 ISO-8859-1 解码。这两个操作是错误的。

    其次,您几乎肯定不想同时解码和编码。在 Perl 中处理字符编码的黄金法则是遵循这个过程:

    1. 从外部世界获取数据后立即解码。这将获取您的输入字节流并将其转换为 Perl 的字符串内部表示。
    2. 根据您的要求处理数据。
    3. 在将数据发送到外界之前对其进行编码。这采用 Perl 对字符串的内部表示,并将其转换为正确编码的字节流,用于您所需的输出编码。

    【讨论】:

      猜你喜欢
      • 2015-05-15
      • 2020-04-22
      • 2010-09-17
      • 2011-06-02
      • 2015-12-28
      • 2012-01-20
      • 1970-01-01
      • 2011-10-25
      • 1970-01-01
      相关资源
      最近更新 更多