Perl - 文件编码和单词比较

时间:2011-05-05 17:13:23

标签: perl unicode character-encoding

我有一个文件,其中每行都有一个短语/术语,我从STDIN读取perl。我有一个停用词列表(如“á”,“são”,“é”),我希望将每个词与每个词进行比较,如果它们相等则删除。问题是我不确定文件的编码格式。

我从file命令得到了这个:

words.txt: Non-ISO extended-ASCII English text

我的linux终端是UTF-8,它显示了某些单词的正确内容,而其他单词则没有。以下是其中一些的输出:

condi<E3>
conte<FA>dos
ajuda, mas não resolve
mo<E7>ambique
pedagógico são fenómenos

您可以看到第3行和第5行正确识别带有重音符号和特殊字符的单词,而其他行则没有。其他行的正确输出应该是:condiã,conteúdos和moçambique。

如果我使用binmode(STDOUT, utf8),则“错误”行现在可以正确输出,而其他行则不能。例如第3行:

  

ajuda,masnão resolve

我该怎么办?

2 个答案:

答案 0 :(得分:4)

我强烈建议您创建一个过滤器,该过滤器将带有混合编码行的文件转换为纯UTF-8。然后是

open(INPUT, "< badstuff.txt") || die "open failed: $!";

您可以打开固定版本或修复程序中的管道,例如:

open(INPUT, "fixit < badstuff.txt |") || die "open failed: $!"

在任何一种情况下,你都会

binmode(INPUT, ":encoding(UTF-8)") || die "binmode failed";

然后fixit程序可以这样做:

use strict;
use warnings;
use Encode qw(decode FB_CROAK);

binmode(STDIN,  ":raw")  || die "can't binmode STDIN";
binmode(STDOUT, ":utf8") || die "can't binmode STDOUT";

while (my $line = <STDIN>) {
    $line = eval { decode("UTF-8", $line, FB_CROAK() };
    if ($@) { 
        $line = decode("CP1252", $line, FB_CROAK()); # no eval{}!
    }
    $line =~ s/\R\z/\n/;  # fix raw mode reads
    print STDOUT $line;    
}

close(STDIN)  || die "can't close STDIN: $!";
close(STDOUT) || die "can't close STDOUT: $!";
exit 0;

看看它是如何工作的?当然,您可以将其更改为默认为其他一些编码,或者具有多个后退。可能最好在@ARGV中列出它们。

答案 1 :(得分:3)

它的工作原理如下:

C:\Dev\Perl :: chcp
Aktive Codepage: 1252.

C:\Dev\Perl :: type mixed-encoding.txt
eins zwei drei Käse vier fünf Wurst
eins zwei drei Käse vier fünf Wurst

C:\Dev\Perl :: perl mixed-encoding.pl < mixed-encoding.txt
eins zwei drei vier fünf
eins zwei drei vier fünf

mixed-encoding.pl的位置如下:

use strict;
use warnings;
use utf8; # source in UTF-8
use Encode 'decode_utf8';
use List::MoreUtils 'any';

my @stopwords = qw( Käse Wurst );

while ( <> ) { # read octets
    chomp;
    my @tokens;
    for ( split /\s+/ ) {
        # Try UTF-8 first. If that fails, assume legacy Latin-1.
        my $token = eval { decode_utf8 $_, Encode::FB_CROAK };
        $token = $_ if $@;
        push @tokens, $token unless any { $token eq $_ } @stopwords;
    }
    print "@tokens\n";
}

请注意,脚本不必以UTF-8编码。只是如果你的脚本中有时髦的字符数据,你必须确保编码匹配,所以如果你的编码是UTF-8,那么use utf8,如果你的编码不​​是,那就是use strict; use warnings; # source in Latin1 use Encode 'decode'; use List::MoreUtils 'any'; my @stopwords = qw( Käse Wurst ); while ( <> ) { # read octets chomp; my @tokens; for ( split /\s+/ ) { # Try UTF-8 first. If that fails, assume 8-bit encoding. my $token = eval { decode utf8 => $_, Encode::FB_CROAK }; $token = decode Windows1252 => $_, Encode::FB_CROAK if $@; push @tokens, uc $token unless any { $token eq $_ } @stopwords; } print "@tokens\n"; }

根据tchrist的声音建议进行更新:

{{1}}