在Perl文件输出中强制使用UTF-8字节顺序标记

12
我正在使用Perl编写CSV文件。CSV中包含Unicode字符。我使用以下代码将CSV写出:
open(my $fh, ">:utf8", "rpt-".$datestring.".csv")
or die "cannot open < rpt.csv: $!";

文件中的字符被正确地写入,但似乎没有包括UTF8字节顺序标记。这会让我的用户感到困惑,当他们尝试在Excel中打开文件时。有没有一种方法可以强制写入字节顺序标记?

我尝试了以下方式:

print $fh "\x{EFBBBF};

我最终在文件顶部得到了一堆乱码。


3
对于UTF-8来说,添加“字节顺序标记”是没有逻辑意义的,因为UTF-8只有一种可能的字节顺序。我知道某些Windows应用程序依赖于存在“BOM”来触发使用Unicode编码而不是Microsoft代码页,但如果您不需要处理损坏的微软应用程序,那么在UTF8文档中添加BOM是没有价值的。 - Grant McLean
@Grant:或者,严谨地说:由于UTF-8编码为字节流,因此没有字节顺序。字节顺序(或字节序)仅对多字节数字有意义。 - musiKk
2
@Grant 我原则上同意您的观点。但我的用户正在使用有问题的 MS 应用程序。因此需要强制使用 BOM。 - Carl Bullard
1
强制使用BOM听起来无论如何都是个好主意,否则仅从流中就无法确定其编码方式。 - chrisvarnz
2
“UTF-8的'字节顺序标记'在逻辑上没有意义”——这是错误的。虽然基于一个错误的观念,即名称决定了事物的语义,但即使这个观念是正确的,它也是错误的……因为在utf8文件中存在/不存在BOM可以被认为是在转换为utf16或utf32文件时存在/不存在BOM,从而实现透明的往返转换。“如果你不处理损坏的MS应用程序”OP明确提到了Excel。问题不是关于是否应该使用BOM,而是如何输出它们,所以整个学究式的探讨都是不合适的。 - Jim Balter
2个回答

14

尝试这样做:

print $fh chr(65279);
打开文件后。

11
use File::BOM (); open my $fh, '> :utf8 :via(File::BOM)', … 可以更加清晰明确一些。 - daxim
1
这不是UTF-16 BOM吗?他应该这样做: print $fh pack("CCC",0xef,0xbb,0xbf); 虽然这么说,我只能让期望BOM的FusionCharts理解你的例子。 - Cosmicnet
3
@Cosmicnet:不是的,所有的UTF字符集都使用相同的代码点来表示BOM。区别在于文件句柄上启用的编码层。请参见问题中open调用中的:utf8 - dolmen
@MooingDuck,问题的标题和内容都反复提到了UTF-8;没有涉及到UTF-16。你的假设似乎基于对Unicode的误解。 - Jim Balter

0
是否有一种方法可以强制写入字节顺序标记(Byte Order Mark)?
为了实现这一点,你必须在打开文件时使用File::BOM来写入字节顺序标记。
例如,写入一个带有字节顺序标记的小端UTF-16文件:
use File::BOM ();
my $filename = "out.bin";
open(FH, '>:encoding(UTF-8):via(File::BOM)', $filename);
print FH "ʇsǝ⊥\n";

然后运行程序并检查输出:
% file out.bin
out.bin: Unicode text, UTF-8 (with BOM) text

在 Perl 5.8.7 之前,存在宽字符的错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接