来自文件的Perl和utf8输出[重复]

svdrlsy4  于 2022-11-15  发布在  Perl
关注(0)|答案(2)|浏览(147)

此问题在此处已有答案

How can I output UTF-8 from Perl?(6个答案)
三个月前关门了。
我有一个问题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

有人能帮帮我吗?

ki0zmccv

ki0zmccv1#

解码你的输入,编码你的输出。你有两个错误与未能正确解码和编码有关。
具体来说,你错过了

use utf8;
use open ":std", ":encoding(UTF-8)";

详情如下。
Perl源代码应该是ASCII(带有8位干净的字符串文字),除非您使用use utf8告诉Perl它是UTF-8。
我相信你有一个UTF-8终端。我们可以从cat 02.pl工作的事实中得出结论,你的源代码是用UTF-8编码的。这意味着Perl看到的是这样的等价物:

print "pr\x{C3}\x{A9}f\x{C3}\x{A9}r\x{C3}\x{A9}\n";   # C3 A9 = é encoded using UTF-8

您应该使用use utf8;,这样Perl就可以看到

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 pragma使它变得更加简洁。

#!/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;
2ledvvac

2ledvvac2#

UTF-8是一个有趣的问题。首先,你的Perl本身会正确打印,因为你没有做任何UTF-8处理。你有一个UTF-8字符串,但Perl本身并不真正知道它是UTF-8,它也会按原样打印它。
UTF-8终端。一切看起来都很好。即使不是这样。
当你把use utf8;添加到你的源代码中时,你会看到,你的print现在会产生同样的垃圾。但是如果你有包含UTF-8的字符串,那就是你应该做的。

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;

这可能是乏味的。但是您可以使用binmode在FileHandle上启用自动编码

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';

相关问题