为什么PerlIO :: encoding插入额外的utf8层?

时间:2015-07-09 19:27:42

标签: perl encoding

documentation for PerlIO说:

  

:编码使用:编码(ENCODING)在open()或binmode()中   安装一个透明地进行字符集和编码的层   转换,例如从Shift-JIS到Unicode。注意   在stdio下:编码也启用:utf8。请参阅PerlIO :: encoding for   更多信息。

这是一个测试脚本:

use feature qw(say);
use strict;
use warnings;

my $fn = 'test.txt';
for my $mode ('>', '>:encoding(utf8)' ) {
    open( my $fh, $mode, $fn);
    say  join ' ', (PerlIO::get_layers($fh));
    close $fh;
}

输出是:

unix perlio
unix perlio encoding(utf8) utf8

为什么我在这里获得额外的utf8图层?

1 个答案:

答案 0 :(得分:8)

由于需要了解Perl内部的原因。

当您将数字4存储在标量中时,它可以存储为有符号整数,无符号整数或浮点数。您不知道使用了哪个,并且您没有任何理由关心使用哪个。 Perl会根据需要自动转换。

字符串也是如此。它们有两种存储格式。你的名字就是一个很好的例子。 “HåkonHægland”可以存储为

48.E5.6B.6F.6E.20.48.E6.67.6C.61.6E.64

48.C3.A5.6B.6F.6E.20.48.C3.A6.67.6C.61.6E.64

名为UTF8的标志表示存储格式的选择。这对用户来说是透明的(或者至少应该是这样)。

$ perl -Mutf8 -E'
    $_ = "Håkon Hægland";
    utf8::downgrade( $d = $_ );  # Converts to the first format mentioned above.
    utf8::upgrade(   $u = $_ );  # Converts to the second format mentioned above.
    say $d eq $u ? "eq" : "ne";
'
eq

虽然它对你来说是透明的,但它对Perl本身来说远非透明。每当你操作一个字符串时,Perl必须检查它存储的存储格式。例如,如果你连接两个字符串,Perl必须确保它们在执行连接之前使用相同的存储格式,必要时转换一个。

PerlIO也不透明。与Perl的其余部分一样,PerlIO必须处理字符串缓冲区中的字节,而不是您在Perl级别上看到的字节。有时,这些字节注定是标量的字符串缓冲区,其中UTF8标志被清除,有时,这些字节注定是设置了UTF8标志的标量的字符串缓冲区。 PerlIO需要跟踪它。当通过读取句柄获得的标量需要设置:utf8标志时,PerlIO不会在层与层之间携带标记,而是添加UTF8层。

因此,:encoding转换形成

的字节
Håkon Hægland

从指定的编码到

48.C3.A5.6B.6F.6E.20.48.C3.A6.67.6C.61.6E.64

:utf8导致标量设置UTF8标志,导致生成的标量包含

U+0048.00E5.006B.006F.006E.0020.0048.00E6.0067.006C.0061.006E.0064