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

Håk*_*and 5 perl encoding

PerlIO文档说:

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

这是一个测试脚本:

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;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

unix perlio
unix perlio encoding(utf8) utf8
Run Code Online (Sandbox Code Playgroud)

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

ike*_*ami 8

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


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

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

48.E5.6B.6F.6E.20.48.E6.67.6C.61.6E.64
Run Code Online (Sandbox Code Playgroud)

或者作为

48.C3.A5.6B.6F.6E.20.48.C3.A6.67.6C.61.6E.64
Run Code Online (Sandbox Code Playgroud)

标志名称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
Run Code Online (Sandbox Code Playgroud)

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

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


因此,:encoding转换形成的字节

Håkon Hægland
Run Code Online (Sandbox Code Playgroud)

从指定的编码到

48.C3.A5.6B.6F.6E.20.48.C3.A6.67.6C.61.6E.64
Run Code Online (Sandbox Code Playgroud)

:utf8导致标有UTF8标志设置,导致产生的标遏制

U+0048.00E5.006B.006F.006E.0020.0048.00E6.0067.006C.0061.006E.0064
Run Code Online (Sandbox Code Playgroud)