4

我正在编写一个脚本,它将一个 UTF-16 编码的文本文件作为输入并输出一个 UTF-16 编码的文本文件。

use open "encoding(UTF-16)";

open INPUT, "< input.txt"
   or die "cannot open > input.txt: $!\n";
open(OUTPUT,"> output.txt");

while(<INPUT>) {
   print OUTPUT "$_\n"
}

假设我的程序将 input.txt 中的所有内容写入 output.txt。

这在我的 cygwin 环境中工作得非常好,它使用“这是为 cygwin-thread-multi-64int 构建的 perl 5,版本 14,subversion 2 (v5.14.2)”

但是在我的 Windows 环境中,它使用的是“这是为 MSWin32-x64-multi-thread 构建的 perl 5,版本 12,subversion 3 (v5.12.3)”,

output.txt 中的每一行除了第一行外都带有疯狂的符号。

例如:

<FIRST LINE OF TEXT>
਀    ㈀  ㄀Ⰰ ㈀Ⰰ 嘀愀 ㌀ 䌀栀椀愀 䐀⸀⸀⸀  儀甀愀渀最 䠀ഊ&lt;SECOND LINE OF TEXT>
...

谁能提供一些关于为什么它适用于 cygwin 而不是 windows 的见解?

编辑:按照建议打印编码层后。

在 Windows 环境中:

unix
crlf
encoding(UTF-16)
utf8
unix
crlf
encoding(UTF-16)
utf8

在 Cygwin 环境中:

unix
perlio
encoding(UTF-16)
utf8
unix
perlio
encoding(UTF-16)
utf8

唯一的区别是 perlio 和 crlf 层。

4

2 回答 2

5

[我本来打算等待并给出一个彻底的答案,但如果我给你一个快速的答案可能比什么都不做要好。]

问题是层crlfencoding顺序错误。不是你的错。

例如,假设您print "a\nb\nc\n";使用 UTF-16le(因为它更简单,而且可能是您真正想要的)。你最终会得到

61 00 0D 0A 00 62 00 0D 0A 00 63 00 0D 0A 00

代替

61 00 0D 00 0A 00 62 00 0D 00 0A 00 63 00 0D 00 0A 00

我认为您无法使用open编译指示或使用获得正确的结果binmode,但可以使用open.

open(my $fh, '<:raw:encoding(UTF-16):crlf', $qfn)

您需要附加:utf8一些旧版本 IIRC。

它适用于 cygwin,因为该crlf层仅在 Windows 上添加。你会得到

61 00 0A 00 62 00 0A 00 63 00 0A 00
于 2012-10-28T07:00:41.537 回答
4

您的编码中有错字。应该use open ":encoding(UTF-16)" 注意冒号。我不知道为什么它可以在 Cygwin 而不是 Windows 上工作,但也可能是 5.12 与 5.14 的事情。Perl 似乎弥补了它,但它可能是导致您的问题的原因。

如果不这样做,请检查编码是否应用于您的文件句柄。

print map { "$_\n" } PerlIO::get_layers(*INPUT);
print map { "$_\n" } PerlIO::get_layers(*OUTPUT);

使用词法文件句柄(即。open my $fh, "<", $file)。Glob 文件句柄是全局的,因此程序中的其他东西可能会干扰它们。

如果一切顺利,如果词法文件句柄得到encoding(UTF-16)应用,请告诉我们,我们可以尝试其他方法。

更新: 这可能会提供您的答案:“ BOM ed UTF 文件不适合流模型,它们必须作为二进制文件来代替。 ”看起来您必须以二进制形式读取文件并将编码作为字符串进行。这可能是 5.14 中修复的错误。

更新 2:是的,我可以确认这是5.14 中修复的错误

于 2012-10-28T00:54:02.183 回答