Sow*_*der 1 perl utf-8 character-encoding
我是Perl脚本的新手,我在解码字符串时面临一些问题:
use HTML::Entities;
my $string='Rémunération €';
$string=decode_entitie($string);
print "$string";
Run Code Online (Sandbox Code Playgroud)
我得到的输出看起来像Rémunération €它应该是什么样子Rémunération €.
有人可以帮我这个吗?
如果您在终端上运行此版本的代码(在decode_entities固定,严格模式和警告启用,以及额外print添加的拼写错误):
use strict;
use warnings;
use HTML::Entities;
my $string='Rémunération €';
print "$string\n";
$string=decode_entities($string);
print "$string\n";
Run Code Online (Sandbox Code Playgroud)
你应该看到以下输出:
Rémunération €
Wide character in print at test.pl line 7.
Rémunération €
Run Code Online (Sandbox Code Playgroud)
以下是一系列事件:
您的代码是用UTF-8编写的,但是没有use utf8;,因此Perl会逐字节地解析您的源代码(特别是其中的任何字符串文字).因此,字符串文字'é'被解析为两个字符的字符串,因为UTF-8编码é占用两个字节.
通常,这并不重要(多),因为你STDOUT也不是UTF-8模式,所以它只需要你给它的任何字节字符串并逐字节地吐出,然后你的终端将结果输出解释为UTF-8(或尝试).
所以,当你做print 'é';Perl认为你在字节模式下打印一个双字符串,并写出两个字节,这恰好构成了单个字符的UTF-8编码é.
但是,当您运行字符串时decode_entities(),它会将其解码€为实际的Unicode €字符,该字符不适合单个字节.
当您尝试打印生成的字符串时,Perl会注意到"宽" €字符.它不能将它作为单个字节打印出来,所以相反,它会回退到将整个字符串编码为UTF-8(并发出警告,如果您启用了这些,则应该如此).但是这会导致és(已经编码,因为Perl在解析代码时从未解码它们)以获得双UTF8编码,从而产生你看到的mojibake输出.
一个简单的解决方法是添加use utf8;到您的代码中,并默认将所有文件句柄(包括STDIN/ STDOUT/ STDERR)设置为UTF-8模式,例如:
use utf8;
use open qw(:std :utf8);
Run Code Online (Sandbox Code Playgroud)
将这些行添加到上面的测试脚本之前,您获得的输出应为:
Rémunération €
Rémunération €
Run Code Online (Sandbox Code Playgroud)