关于unicode:如何在Perl中将输入文件转换为UTF-8编码?

How can I convert an input file to UTF-8 encoding in Perl?

我已经知道如何使用如下代码将文件中非UTF8编码的内容逐行转换为UTF-8编码:

1
2
3
4
5
6
7
# outfile.txt is in GB-2312 encode    
open my $filter,"<",'c:/outfile.txt';

while(<$filter>){
#convert each line of outfile.txt to UTF-8 encoding  
    $_ = Encode::decode("gb2312", $_);
...}

但是我认为Perl可以将整个输入文件直接编码为utf-8格式,所以我尝试了类似的方法

1
2
#outfile.txt is in GB-2312 encode
open my $filter,"<:utf8",'c:/outfile.txt';

(Perl说类似于"utf8"的内容,"xd4"不映射到Unicode)

1
2
open my $filter,"<",'c:/outfile.txt';
$filter = Encode::decode("gb2312", $filter);

(Perl在未打开的文件句柄上说"readline()"

它们不工作。但是有没有办法直接将输入文件转换成UTF-8编码?

更新:

看起来事情不像我想的那么简单。现在我可以用一种迂回的方式将输入文件转换为UTF-8代码。我首先打开输入文件,然后将其内容编码为UTF-8,然后输出到新文件,然后打开新文件进行进一步处理。这是代码:

1
2
3
4
5
6
open my $filter,'<:encoding(gb2312)','c:/outfile.txt';
open my $filter_new, '+>:utf8', 'c:/outfile_new.txt';
print $filter_new $_ while <$filter>;
while (<$filter_new>){
...
}

但这是太多的工作,它甚至比简单地逐行编码$filter的内容更麻烦。


我想我误解了你的问题。我认为您要做的是以非UTF-8编码读取文件,然后在程序中以UTF-8格式处理数据。这样做容易多了。使用正确的编码读取数据后,Perl在内部将其表示为UTF-8。所以,做你必须做的。

当你把它写出来时,使用你想保存为的任何编码。但是,您不必将其放回文件中即可使用。

旧答案

PerlI/O层只读取数据,前提是它已经正确编码。它不会为您转换编码。告诉open使用utf8,就是说它已经是utf8了。

您必须按照所示使用编码模块(除非您想编写自己的I/O层)。您可以将字节转换为UTF-8,或者如果您知道编码,您可以从一种编码转换为另一种编码。因为看起来您已经知道编码,所以可能需要from_to()函数。

如果您刚开始使用Perl和Unicode,那么在做任何事情之前,请先阅读Juerd的PerlUnicode建议。


:编码层将返回适合Perl使用的utf-8。也就是说,Perl将把每个字符识别为一个字符,即使它们是多个字节。根据接下来要对数据做什么,这可能是足够的。

但是,如果您对Perl试图将其从utf8降级的数据执行某些操作,那么您要么需要告诉Perl不要(例如,执行binmode(stdout,":utf8")来告诉Perl输出到stdout应该是utf8),要么需要Perl将utf8视为二进制数据(分别解释每个字节,并且不知道utf8字符。)

要做到这一点,您所需要的就是为您的开放应用一个额外的层:

1
open my $foo,"<:encoding(gb2312):bytes", ...;

请注意,以下输出将是相同的:

1
2
perl -we'open my $foo,"<:encoding(gb2312):bytes","foo"; $bar = <$foo>; print $bar'
perl -CO -we'open my $foo,"<:encoding(gb2312)","foo"; $bar = <$foo>; print $bar'

但在一种情况下,Perl知道读取的数据是utf8(因此length($bar)将报告utf8字符的数量),并且必须明确告诉(by-co)stdout将接受utf8,而在另一种情况下,Perl对数据不做任何假设(因此length($bar)将报告字节数),并按原样打印出来。