Sin*_*nür 19 c windows perl utf-8
正如@ikegami建议的那样,我将此报告为一个错误.
错误#121783 for perl5:Windows:cmd.exe中的UTF-8编码输出,代码页65001导致意外输出
考虑以下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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
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}"
??????
当代码页设置为65001时,从cmd.exe中的perl程序打印时导致最后一个八位字节输出的原因是什么?
PS:我的博客上有更多的信息和截图.对于这个问题,我试图将所有事情提炼到最简单的情况.
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}"
??????
以下程序生成正确的输出:
use utf8;
use strict;
use warnings;
use warnings qw(FATAL utf8);
binmode(STDOUT, ":unix:encoding(utf8):crlf");
print '???xyz', "\n";
Run Code Online (Sandbox Code Playgroud)
输出:
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";
Run Code Online (Sandbox Code Playgroud)
给我:
--- - unix - '' - 0x01205200 - crlf - '' - 0x00c85200 - unix - '' - 0x01201200 - encoding - utf8 - 0x00c89200 - crlf - '' - 0x00c8d200 ???xyz
和以前一样,我不知道这个的全部后果.我打算perl在某个时候构建一个调试来进一步诊断它.
我进一步研究了这一点.以下是该帖子的一些观察结果:
第一unix层的标志是0x01205200 = CANWRITE | TRUNCATE | CRLF | OPEN | NOTREG.为什么在Windows上CRLF为unix图层设置?我不知道内部是否足以理解这一点.
但是,第二unix层的标志是我的显式推送的标志binmode,是0x01201200 = 0x01205200&~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标志.
| 归档时间: |
|
| 查看次数: |
509 次 |
| 最近记录: |