正如@ikegami建议的那样,我将此报告为一个错误。
考虑以下C和Perl程序,它们都在标准输出上输出字符串“αβγ”的UTF-8编码:
#include <stdio.h>
int main(void) {
/* UTF-8 encoded alpha, beta, gamma */
char x[] = { 0xce, 0xb1, 0xce, 0xb2, 0xce, 0xb3, 0x00 };
puts(x);
return 0;
}
输出:
C:\…> chcp 65001 Active code page: 65001 C:\…> cttt.exe αβγ
C:\…> perl -e "print qq{\xce\xb1\xce\xb2\xce\xb3\n}" αβγ �
据我所知,最后一个八位字节0xb3
正在另一行输出,正在被翻译为U+FFFD
。
请注意,重定向输出会消除此效果。
我还可以验证它是重复的最后一个八位字节:
C:\…> perl -e "print qq{\xce\xb1\xce\xb2\xce\xb3xyz\n}" αβγxyz z
另一方面,syswrite避免了这个问题。
C:\…> perl -e "syswrite STDOUT, qq{\xce\xb1\xce\xb2\xce\xb3xyz\n}" αβγxyz
我在Windows 8.1 Pro 64位和Windows Vista Home 32位的cmd.exe窗口中使用自构建的perl 5.18.2和ActiveState的5.16.3观察到这一点。
我没有在Cygwin,Linux或Mac OS X环境中看到问题。此外,Cygwin的perl 5.14.4在cmd.exe中生成正确的输出。
此外,当代码页设置为437时,C和Perl版本的输出都是相同的:
C:\…> chcp 437 Active code page: 437 C:\…> cttt.exe ╬▒╬▓╬│ C:\…> perl -e "print qq{\xce\xb1\xce\xb2\xce\xb3\n}" ╬▒╬▓╬│
当code page is set to 65001时,在cmd.exe中从perl程序打印时,导致上一个八位字节输出的原因是什么?
PS:我在my blog上有更多信息和截图。对于这个问题,我试图将一切都提炼到最简单的情况。
PPS:抛弃\n
导致更有趣的事情:
C:\…> perl -e "print qq{\xce\xb1\xce\xb2\xce\xb3xyz}" αβγxyzxyz
C:\…> perl -e "print qq{\xce\xb1\xce\xb2\xce\xb3}" αβγ�γ�
答案 0 :(得分:5)
以下程序生成正确的输出:
use utf8;
use strict;
use warnings;
use warnings qw(FATAL utf8);
binmode(STDOUT, ":unix:encoding(utf8):crlf");
print 'αβγxyz', "\n";
输出:
C:\…> chcp 65001 Active code page: 65001 C:\…> perl pttt.pl αβγxyz
这似乎向我表明:crlf
层有一些愚蠢。我不明白内部足以在此时智能地评论这一点。
经过多次实验,我得出的结论是,如果控制台已设置为65001代码页,binmode(STDOUT, ":unix:encoding(utf8):crlf");
将“正常”。但请注意以下事项:
binmode(STDOUT, ":unix:encoding(utf8):crlf");
print Dump [
map {
my $x = defined($_) ? $_ : '';
$x =~ s/\A([0-9]+)\z/sprintf '0x%08x', $1/eg;
$x;
} PerlIO::get_layers(STDOUT, details => 1)
];
print "αβγxyz\n";
给了我:
--- - unix - '' - 0x01205200 - crlf - '' - 0x00c85200 - unix - '' - 0x01201200 - encoding - utf8 - 0x00c89200 - crlf - '' - 0x00c8d200 αβγxyz
和以前一样,我不知道这一点的全部后果。我打算在某个时候构建调试perl
以进一步诊断它。
我examined this a little further。以下是该帖子的一些观察结果:
第一个unix
图层的标记为0x01205200 = CANWRITE | TRUNCATE | CRLF | OPEN | NOTREG
。为什么在Windows上为CRLF
图层设置了unix
?我不知道内部是否足以理解这一点。
然而,第二个unix
图层的标记是我的显式binmode
推送的标记,是0x01201200 = 0x01205200&amp; 〜CRLF。这对我来说是有意义的。
第一个crlf图层的标志是0x00c85200 = CANWRITE | TRUNCATE | CRLF | LINEBUF | FASTGETS | TTY
。我在layer
图层之后推送的第二个:encoding(utf8)
的标记为0x00c8d200 = 0x00c85200 | UTF8
。
现在,如果我使用open my $fh, '>:encoding(utf8)', 'ttt'
打开文件,并转储相同的信息,我会得到:
--- - unix - '' - 0x00201200 - crlf - '' - 0x00405200 - encoding - utf8 - 0x00409200
正如所料,unix
图层未设置CRLF
标记。