2012-08-03 188 views
3

我已经给出了一个文件,(可能)以Latin-1(ISO 8859-1)编码,并且有一些转换和数据挖掘可以用它来完成。输出应该是UTF-8格式的,我试过了关于Perl中编码转换的所有东西,但都没有产生任何可用的输出。在Perl中正确处理UTF-8

我知道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, '<:encoding(ISO-8859-1)', $ARGV[0] or die $!;等等。结果是混乱的元音变音,或者像\xC3 is not a valid UTF-8 character这样的错误信息,或者甚至是混合文本(一些是UTF-8,一些是拉丁语-1)。

我想要的只是一个简单的方法来读取拉丁文-1文本文件并通过print在控制台上生成UTF-8输出。有什么简单的方法来在Perl中做到这一点?

+0

Perl不知道,如何用utf正常工作:( – gaussblurinc 2012-08-03 09:28:50

+2

loldop,这是错误的。 – daxim 2012-08-03 09:32:20

回答

5

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; 
    } 
    
+0

daxim的方法会遇到的唯一问题是,如果文件实际上不是Latin1 - 混合编码中的文件是一个噩梦来处理,不管你做什么不幸。 – 2012-08-03 09:44:26

+0

@RichardHuxton有没有处理这些问题的机会?我怀疑我提供了一些混合编码的数据。 – Lanbo 2012-08-03 15:17:50

+1

有Encode :: Guess,但恐怕几乎不可能将许多8位字符集分开,而不提前知道内容是什么。例如8859-15具有欧元符号,因此具有许多代码点0xA4的财务信息可能是8859-1而非8859-1。同样一些威尔士重音字符在8859-14。不知道文本的意思是什么,这是非常艰苦的工作。这并没有引起人们从Word中剪切+粘贴的Microsoft-Word“智能报价”的出现。 – 2012-08-03 15:36:10

5

可能为:

$_ = 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__ 
Â׶ذÂÔË»á 
3
$_ = decode('ISO-8859-1', encode('UTF-8', $_)); 

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

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

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