Perl utf8 binmode出乎意料的结果

时间:2017-09-05 20:50:22

标签: xml perl utf-8

为什么binmode作为原始产生变音符号?可以详细说明苏黎世'字符串存储在Perl内部?只是有点失落。

use strict;
use warnings;

my $filename = "result-test-encoding-raw.xml";
open(my $fh,'>', $filename) or die "die";
#binmode $fh, ':utf8'; #bad umlaut
binmode $fh, ':raw'; #good umlaut

print $fh '<?xml version="1.0" encoding="UTF-8"?>';
print $fh '<node>';

my $line_text =  'Zürich';
print $fh $line_text;
print $fh '   next   ';
$line_text = 'Z&#252;rich';
print $fh $line_text;

print $fh '</node>';

close($fh);

2 个答案:

答案 0 :(得分:4)

您错过了use utf8;,它告诉Perl您的源代码是使用UTF-8编码的。

默认情况下,源文件应使用US-ASCII进行编码。

  • 如果您使用UTF-8对源文件进行编码,但是您没有告诉Perl(使用use utf8;),Perl会将其视为使用US-ASCII进行编码。对于字符串文字,Perl只是将字节映射到字符串字符(而不是拒绝非ASCII字符)。这意味着$line_text包含5A.C3.BC.72.69.63.68

    当您将这些字符传递给带有编码层的文件句柄时,编码层会将这些字符视为Unicode代码点(Zürich)并生成相应的字节来表示这些字符。

    < / LI>
  • 如果您使用UTF-8对源文件进行编码,并且如果您将其告知Perl(使用use utf8;),则Perl会将其视为使用UTF-8进行编码(相应地对其进行解码)。这意味着$line_text包含5A.FC.72.69.63.68

    当您将这些字符传递给带有编码层的文件句柄时,编码层会将这些字符视为Unicode代码点(Zürich)并生成相应的字节来表示这些字符。

    < / LI>
use strict;
use warnings;
use utf8;                             # Source code is encoded using UTF-8.
use open ':std', ':encoding(UTF-8)';  # Terminal expects UTF-8. Default encoding for files.

my $filename = "result-test-encoding-raw.xml";

open(my $fh, '>', $filename)
   or die("Can't create \"$filename\": $!\n");

...    
print $fh 'Zürich';
...

请注意,我使用:encoding(UTF-8)代替:utf8。后者是不正确的,即使在这个例子中两者看起来都是等价的。

答案 1 :(得分:0)

Perl中的字符串可以存储为字节字符串或Unicode字符串。在您的情况下,您正在定义Byte Strings。

问题:您的程序源保存在哪种编码中?

您对$line_text的第一个作业是程序源编码中的字节字符串。使用:raw将此字节字符串打印到文件时,它将完全按照存储在源中的方式进行转储。如果使用编码器打印编码的字节串,如:utf8,则会得到一个双重编码的字符串,这不太可能是一个好主意。如果您的程序以UTF8保存,那么您可以use utf8;将该字符串文字解码为字符串。当您使用:utf8打印正确解码的字符串时,它会字符正确编码为UTF8。

故事的道德:虽然传递原始字节在某些情况下可以正常工作,但解码输入(和字符串文字)并对输出进行编码通常更好。