Perl 在Windows上使用BOM和CRLF行分隔符创建UTF-16LE

Perl 在Windows上使用BOM和CRLF行分隔符创建UTF-16LE,perl,unicode,newline,utf-16,byte-order-mark,Perl,Unicode,Newline,Utf 16,Byte Order Mark,我需要在Windows7框中生成一些带有CRLF行分隔符的UTF-16LE编码文件。(目前使用的是草莓5.20.1) 我需要花很长时间才能得到正确的输出,我想知道我的解决方案是否是正确的方法,因为对于Perl中的其他语言来说,它似乎过于复杂了。特别是: 为什么Perl使用正确的BOM和编码(UTF-16)生成有效的UTF-16大端码,而如果我使用UTF-16LE或UTF-16BE而不使用额外的包文件::BOM,则没有BOM 为什么CRLF处理看起来像是有问题的(它被输出为0d0a00而不是0d

我需要在Windows7框中生成一些带有CRLF行分隔符的UTF-16LE编码文件。(目前使用的是草莓5.20.1)

我需要花很长时间才能得到正确的输出,我想知道我的解决方案是否是正确的方法,因为对于Perl中的其他语言来说,它似乎过于复杂了。特别是:

  • 为什么Perl使用正确的BOM和
    编码(UTF-16)
    生成有效的UTF-16大端码,而如果我使用
    UTF-16LE
    UTF-16BE
    而不使用额外的包
    文件::BOM
    ,则没有BOM
  • 为什么
    CRLF
    处理看起来像是有问题的(它被输出为
    0d0a00
    而不是
    0d00a00
    ),而没有一些过滤器的旋转?我怀疑对于一种有这么多用户的语言来说,这可能是一个真正的bug
这里是我的评论尝试,我发现正确的是最后的陈述

use strict;
use warnings;
use utf8;
use File::BOM;
use feature 'say';

my $UTF;
my $data = "Hello, héhé, 中文.\nsecond line : my 2€"; # 中文 = zhong wen = chinese

# UTF16 BE + BOM but incorrect CRLF: "0D 0A 00" instead of "0D 00 0A 00"
open $UTF, ">:encoding(UTF-16)", "utf-16-std-be.txt" or die $!;
say $UTF $data;
close $UTF;

# same as UTF-16BE (no BOM, incorrect CRLF)
open $UTF, ">:encoding(ucs2)", "utf-ucs2.txt" or die $!;
say $UTF $data;
close $UTF;

# UTF16 BE, no BOM, incorrect CRLF
open $UTF, ">:encoding(UTF-16BE)", "utf-16-be-nobom.txt" or die $!;
say $UTF $data;
close $UTF;

# UTF16 LE, no BOM, incorrect CRLF
open $UTF, ">:encoding(UTF-16LE)", "utf-16-le-nobom-wrongcrlf.txt" or die $!;
say $UTF $data;
close $UTF;

# UTF16 LE, BOM OK but still incorrect CRLF
open $UTF, ">:encoding(UTF-16LE):via(File::BOM)", "utf-16-le-bom-wrongcrlf.txt" or die $!;
say $UTF $data;
close $UTF;

# UTF16 LE non raw incorrect 
# (crlf by default on windows) -> 0A => 0D 0A
open $UTF, ">:encoding(UTF-16LE):via(File::BOM)", "utf-16-le-bom-wrongcrlf2.txt" or die $!;
print $UTF $data, "\x0a"; # 0A is magically expanded to 0D 0A but wrong
close $UTF;

# UTF16 LE + BOM + LF 
# raw -> 0A => 0A
# could be correct on UNIX but I need CRLF
open $UTF, ">raw::encoding(UTF-16LE):via(File::BOM)", "utf-16-le-bom-wrongcrlf3.txt" or die $!;
say $UTF $data;
close $UTF;

# manual BOM, but CRLF OK
open $UTF, ">:raw:encoding(UTF-16LE):crlf", "utf-16-le-bommanual-crlfok.txt" or die $!;
print $UTF "\x{FEFF}";
say $UTF $data;
close $UTF;

#auto BOM, CRLF OK ?
#incorrect, says utf8 "\xA9" does not map to Unicode at c:/perl/Dwimperl-5.14/perl/lib/Encode.pm line 176.
# But I cannot see where the A9 comes from ??!
#~ open $UTF, ">:raw:encoding(UTF-16LE):via(File::BOM):crlf", "utf-16-le-autobom-crlfok1.txt" or die $!;
#~ print $UTF $data;
#~ say $UTF $data;
#~ close $UTF;

# WTF? \n becomes 0D 00 0D 0A 00
open $UTF, ">:encoding(UTF-16LE):crlf:via(File::BOM)", "utf-16-le-autobom-crlf2.txt" or die $!;
say $UTF $data;
close $UTF;

#CORRECT WAY?? : Automatic BOM, CRLF is OK
open $UTF, ">:raw:encoding(UTF-16LE):crlf:via(File::BOM)", "utf-16-le-autobom-crlfok3.txt" or die $!;
say $UTF $data;
close $UTF;
手动BOM,但CRLF正常

是的,以下确实是正确的:

:raw:encoding(UTF-16LE):crlf + manual BOM
  • :raw
    “清除”现有的
    :crlf
    :encoding
  • :编码
    在字节和代码点之间转换
  • :crlf
    在crlf和LF之间转换
所以

读取
===================================================>
代码
+------+字节+----+点+----+点+------+
|文件|------------------:enc |------------------:crlf |--------------------代码|
+------++---+CRLF+----+LF+---+

正如我在中引用的博客文章中提到的,在我看来,
PERLIO_F_CRLF
不应该设置在Windows上最底层的“unix”层上。至少,我是这样读的:“即使在区分
O_文本
O_二进制
的平台上,这一层总是
O_二进制
”@SinanÜnür,
:unix
也使用
O_二进制
作为perliol文档。不添加
:crlf
将使Perl输出对许多程序“不可读”。尝试
perl-e“binmode STDOUT;print qq{a\nb\nc\n}>a.txt和记事本a.txt
它也会弄乱几乎所有读取文本文件的perl代码。请注意,“手动BOM”可以打印为
“\n{BOM}”
,我认为这比将
use File::BOM
:via(File::BOM)
添加到程序更干净。如果您使用的开放模式仅为
UTF-16
,则
Encode
将为您添加BOM表,但假定为编码。如果要影响这一假设,真的应该有办法。如果
open
pragma允许指定多个层,那么可以使用类似
:encoding(UTF-16LE):via(File::BOM):crlf
的东西,这也会很好specified@Borodin,应该是
:via(File::BOM,UTF-16le):crlf
(即
UTF-16le
应该是BOM处理程序的参数),虽然
:via
目前可能不支持该语法。您用正确的方式标记的方法是什么?是推荐的方法,但正如我对ikegami的回答所评论的,我的首选是在打开文件后立即显式打印BOM。您可以通过Unicode名称指定字符,而不是依赖“幻数”FEFF,如
print$UTF“\N{BOM}”
                               Read
        ===================================================>

                               Code                 Code
+------+   bytes   +------+   Points   +-------+   Points   +------+
| File |-----------| :enc |------------| :crlf |------------| Code |
+------+           +------+    CRLF    +-------+     LF     +------+ 

        <===================================================
                               Write