Jon*_*hop 1 perl encoding utf-8
我正在尝试在 Perl 中读取一些 UTF-8 编码的 CSV 文件(至少我相信它们就是这样),并将它们全部写入一个更大的文件中。这是我的脚本:
#!/usr/bin/perl
use strict;
use warnings;
open my $out, '>:encoding(UTF-8)', "output.csv" or die "Cannot open output.csv: $!";
my @files = <*.csv>;
foreach(@files) {
next if $_ =~ m/^output.csv$/;
print "Parsing $_\n";
open my $in, '<:encoding(UTF-8)', $_ or die "Cannot open $_: $!";
while(<$in>) {
chomp;
next if m/^\s*$/;
print $out "$_\n";
}
close $in;
}
close $out;
Run Code Online (Sandbox Code Playgroud)
总而言之,每个文件的内容都以BOM开头,这意味着 BOM 显示为每个文件数据的前三个字节。不应该使用>:encoding(UTF-8)指令打开文件已经摆脱了 BOM 吗?为什么它继续出现在我的输出中?
UTF-8 是一种基于字节的编码,因此字节序无关紧要,并且不需要初始字节顺序标记 (BOM),并且在 UTF-8 数据中通常不鼓励使用。但是它的有效性和功能取决于流行的应用程序,所以 Perl 不能毫无疑问地简单地从数据中剥离它
Unicode BOM 字符U+FEFF与ZERO WIDTH NO-BREAK SPACE字符共享一种编码,因此如果布局是唯一的问题,即使将多个源连接在一起以使其出现在中间数据流
在大多数文件应用程序中,UTF-8 数据源被透明处理,因此仅包含 7 位 ASCII 数据的文件与相同数据的 UTF-8 编码相同。此类数据不得包含 BOM,因为它会干扰透明度。例如,UTF-8 编码的 shell 命令文件开头的shebang #!行不能以字节顺序标记开头,因为 shell 将无法识别它
您可以从解码的Unicode 数据的开头去除 BOM 字符,无论来源如何,使用
s/\A\N{BOM}//
Run Code Online (Sandbox Code Playgroud)
当然,可以通过使用删除锚点的全局替换来删除整个字符串中的字符\A,或者更整洁地使用
tr/\N{BOM}//d
Run Code Online (Sandbox Code Playgroud)
字符流被读取为字节序列,在 16 位或 32 位编码中,您需要知道它是最不重要的(小端)字节还是最重要的(大端)字节首先出现,以便你知道如何将这些字节组合成一个多字节字符
BOM 字符始终为 U+FEFF. 它的全部意义在于这是不变的。所以,如果我从文件中读取的前两个字节和它们FF和FE以该顺序,然后我知道整个文件是UTF-16(或UTF-32)与所述至少-显著字节编码,接着由最显著字节, 或 little-endian, 然后我可以正确解释文件的其余部分
但是字节顺序在基于字节的编码中是没有意义的。每个字符都由一个或多个字节的序列表示,并且无论其原始系统的字节序如何,数据都是相同的。BOM 字符U+FEFF在 UTF-8 中编码为三个十六进制字节EF, BB, BF, 并且是不变的
File::BOM模块在我看来,File::BOM使一个简单的概念不必要地复杂化
如果您必须处理来自具有不同字节序的平台的具有不同编码的许多不同 Unicode 文件,我可以看到它很有用,但在这种情况下,每行文本末尾的记录分隔符的字符序列的变化可能是更多的问题
只要您在打开文件之前知道文件的编码,就应该打开它并根据该标准读取它。如果数据中存在 BOM 字符是一个问题,那么只需使用s///或tr///d删除它。但请记住,在所有符合 Unicode 的系统上都应透明地忽略 BOM 字符