Perl 和 utf8 从文件 [duplicate] 输出

Perl and utf8 output from file [duplicate]

提问人:amir 提问时间:8/13/2022 更新时间:8/13/2022 访问量:269

问:

我对 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

请别人帮帮我吗?

Perl UTF-8

评论

2赞 Shawn 8/13/2022
如果脚本以 utf-8 编码,请添加到脚本中。use utf8;
2赞 Shawn 8/13/2022
并查看编译指示以调整 STDOUT 的编码。use open
1赞 ikegami 8/14/2022
这不是链接问题的重复。相关问题仅涉及OP中的两个问题之一。
0赞 zdim 8/14/2022
"这不是链接问题的复制品“——其次,这不是对给定链接的复制品。而且,这个“机器人”是什么东西——一个程序是否决定这是一个骗局??它“看起来”很相似,是吗?标题的Levenshtein距离很小?(此外,这里给出的 asnwer 远远优于链接页面上的简单方法列表。但是机器人怎么能看到这一点......

答:

3赞 ikegami 8/13/2022 #1

解码输入,编码输出。您有两个与无法正确解码和编码相关的错误。

具体来说,你错过了

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;
1赞 David Raab 8/13/2022 #2

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;

下一个。对于你从外部执行的每个输入,你都需要执行一个 ,并且对于你所做的每个输出。您需要执行 .decodeencode

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