【问题标题】:Perl utf8 binmode unexpected resultsPerl utf8 binmode 意外结果
【发布时间】:2018-02-14 05:36:35
【问题描述】:

为什么 binmode 作为 raw 会产生变音符号?能否详细说明“苏黎世”字符串如何在 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);

【问题讨论】:

  • Re“'Zurich'String在Perl内部是如何存储的”,内部存储格式这里不赘述。

标签: xml perl utf-8


【解决方案1】:

您缺少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) 并生成适当的字节来表示这些字符。

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

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


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。后者是不正确的,尽管在这个例子中两者看起来是等价的。

【讨论】:

  • 默认的 Perl 源编码不是 Latin-1 而不是(7 位)ASCII 吗?至少perldoc perlunifaq 声称如此。
  • @amon,不是我看到的那样。试试perl -MEncode -e'print encode("iso-latin-1", "sub f\xEAte { }\n")' | perl。相比之下,perl -MEncode -e'print encode("UTF-8", "use utf8; sub f\xEAte { }\n")' | perl 工作正常。
  • @amon,当涉及到文字时,它既不是 ASCII 也不是 latin-1(perl -e'print qq{printf "%vX\\n", "\x80";}' | perl 给出了 80,即使 80 都不存在)。它只是将字节直接映射为字符。不过,实际发生的情况实际上更接近 iso-latin-1 而不是 US-ASCII。
【解决方案2】:

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

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

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

故事寓意:虽然在某些情况下传递原始字节可能会起作用,但通常最好对输入(和字符串文字)进行解码并对输出进行编码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-04
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    • 2019-04-08
    • 2012-10-09
    • 2018-09-04
    • 2017-06-02
    相关资源
    最近更新 更多