提问人:amir 提问时间:8/13/2022 更新时间:8/13/2022 访问量:269
Perl 和 utf8 从文件 [duplicate] 输出
Perl and utf8 output from file [duplicate]
问:
我对 perl 输出有问题:法语单词“préféré”有时会输出为“pr f r”:
示例脚本:
devel@k0:~/tmp$ cat 02.pl
#!/usr/bin/env perl
use strict;
use warnings;
print "préféré\n";
open( my $fh, '<:encoding(UTF-8)', 'text' ) ;
while ( <$fh> ) { print $_ }
close $fh;
exit;
执行:
devel@k0:~/tmp$ ./02.pl
préféré
pr�f�r�
devel@k0:~/tmp$ cat text
préféré
devel@k0:~/tmp$ file text
text: UTF-8 Unicode text
请别人帮帮我吗?
答:
解码输入,编码输出。您有两个与无法正确解码和编码相关的错误。
具体来说,你错过了
use utf8;
use open ":std", ":encoding(UTF-8)";
详情如下。
Perl 源代码应该是 ASCII(带有 8 位干净的字符串文字),除非你用来告诉 Perl 它是 UTF-8。use utf8
我相信你有一个 UTF-8 终端。我们可以从这一事实中得出结论,您的源代码是使用 UTF-8 编码的。这意味着 Perl 看到的等价物是这样的:cat 02.pl
print "pr\x{C3}\x{A9}f\x{C3}\x{A9}r\x{C3}\x{A9}\n"; # C3 A9 = é encoded using UTF-8
你应该使用 Perl 看到等价物use utf8;
print "pr\x{E9}f\x{E9}r\x{E9}\n"; # E9 = Unicode Code Point for é
您正确地解码了您读取的文件。
该文件可能包含
70 72 C3 A9 66 C3 A9 72 C3 A9 0A # préféré␊ encoded using UTF-8
由于您添加的编码层,您正在有效地执行
$_ = decode( "UTF-8", "\x{70}\x{72}\x{C3}\x{A9}\x{66}\x{C3}\x{A9}\x{72}\x{C3}\x{A9}\x{0A}" );
或
$_ = "pr\x{E9}f\x{E9}r\x{E9}\n";
这是正确的。
最后,您无法对输出进行编码。
以下操作符合您的要求:
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
BEGIN {
binmode( STDIN, ":encoding(UTF-8)" ); # Well, not needed here.
binmode( STDOUT, ":encoding(UTF-8)" );
binmode( STDERR, ":encoding(UTF-8)" );
}
print "préféré\n";
open( my $fh, '<:encoding(UTF-8)', 'text' ) or die $!;
while ( <$fh> ) { print $_ }
close $fh;
但是杂语使它更干净。
以下操作符合您的要求:open
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use open ":std", ":encoding(UTF-8)";
print "préféré\n";
open( my $fh, '<', 'text' ) or die $!;
while ( <$fh> ) { print $_ }
close $fh;
UTF-8 是一个有趣的问题。首先,你的 Perl 本身会正确打印,因为你不做任何 UTF-8 处理。你有一个 UTF-8 字符串,但 Perl 本身并不知道它是 UTF-8,它也会按原样打印它。
所以一个 UTF-8 终端。一切看起来都很好。即便如此,情况也并非如此。
当您添加到源代码时。你会看到,你的现在将产生同样的垃圾。但是,如果您有包含 UTF-8 的字符串。这是你应该做的。use utf8;
print
use utf8;
# Now also prints garbage
print "préféré\n";
open my $fh, '<:encoding(UTF-8)', 'text';
while ( <$fh> ) {
print $_;
}
close $fh;
下一个。对于你从外部执行的每个输入,你都需要执行一个 ,并且对于你所做的每个输出。您需要执行 .decode
encode
use utf8;
use Encode qw(encode decode);
# Now correct
print encode("UTF-8", "préféré\n");
open my $fh, '<:encoding(UTF-8)', 'text';
while ( <$fh> ) {
print encode("UTF-8", $_);
}
close $fh;
这可能很乏味。但是,您可以在 FileHandle 上启用自动编码binmode
use utf8;
# Activate UTF-8 Encode on STDOUT
binmode STDOUT, ':utf8';
print "préféré\n";
open my $fh, '<:encoding(UTF-8)', 'text';
while ( <$fh> ) {
print $_;
}
close $fh;
现在一切都是 UTF-8!您也可以在 STDERR 上激活它。请记住,如果要在 STDOUT 上打印二进制数据(无论出于何种原因),则必须禁用图层。
binmode STDOUT, ':raw';
评论
use utf8;
use open