我有一个 Perl 脚本,可以解析从多个学区发送给我的数据。我要添加一所新学校,但遇到了以前从未遇到过的问题。当我这样做时$line = <INPUT>
,它会吞掉整个文件而不是一行。
如果我运行file
该文件,它会返回UTF-8 Unicode text, with CRLF, CR line terminators
.我的所有其他文件都返回ASCII text, with CRLF line terminators
。我已经通过 dos2unix 运行它,但它仍然作为一个长字符串运行。当我在 emacs 中编辑它时,它仍然显示 ^M 作为行结尾。
我该如何将这些行结尾转换为可用的行结尾?
更新:供应商向我发送了另一个具有不同行结尾的文件,但仍然不起作用。它们报告为 CRLF、LF。我提取了一个几个样本行。
以下是我的代码的一些片段:
$line = <INPUT> if ($schooldistricts{$schooldistrict}{'header'});
LINE: foreach $line (<INPUT>) {
next LINE unless ($line =~ /\S/);
<do stuff>
}
该文件确实有一个被正确剥离的标头。然后在 foreach 循环中,它成功读取第一行,然后就这样了——就像文件的其余部分是空的一样。
我尝试设置$/
为\r\n\n
,但脚本什么也没做。如果我尝试的话也一样\r\n
。有没有办法明确地查看行结尾编码了哪些字符?
第二次更新:作为实验,我将文件导入 Excel,将其拆分,并将其另存为制表符分隔文件。在服务器上,我运行dos2unix。 Perl 脚本在第二行之后仍然无法解析。File
现在返回UTF-8 Unicode text, with CRLF line terminators
。这是正确的行结尾,因此 Unicode 成为问题。 Unicode 对行结尾的编码方式有什么不同吗?
答案1
perl -pi -e 's/\r\n?/\n/g' your-file
将 CR 字符(可选择后跟 LF)转换为 LF,类似于mac2unix
或dos2unix -c mac
的操作。
或者:
perl -pi -e 's/\r\n?/\r\n/g' your-file
如果这是您的脚本所期望的,则将它们转换为 CRLF(因为例如它将$/
输入记录分隔符设置为"\r\n"
)。
答案2
该管道会将 CR 字符或 CR/LF 序列转换为 LF
tr '\r\n' '\n\r' | sed 's/^\r//g' | tr '\r' '\n'
答案3
使用乐(以前称为 Perl_6)
如果 OP 认为问题是基于 Unicode 的,那么通过 Raku 脚本可能会有所帮助,因为 Raku 默认处理 UTF-8:
~$ cat dos2unix.raku
my $fh1 = open $*IN, :r;
#below use :w (write-only) or :x (:x write-only :exclusive i.e. 'no-clobber')
my $fh2 = open $*OUT, :x, nl-out => "\n";
for $fh1.lines() { $fh2.put($_) };
$fh1.close;
$fh2.close;
将上述文件保存到脚本中(例如“dos2unix.raku”),添加 shebang 行并使其可执行 - 或者只需在命令行中调用它:
~$ raku dos2unix.raku < ends_with_CRLF.txt > ends_with_LF.txt
带有 DOS 行结尾的示例输入(0d 0a
每行):
~$ jot -w '%d' 5 | raku unix2dos.raku | hexdump -C
00000000 31 0d 0a 32 0d 0a 33 0d 0a 34 0d 0a 35 0d 0a |1..2..3..4..5..|
示例输出转换为 Unix 行结尾(0a
每行):
~$ jot -w '%d' 5 | raku unix2dos.raku | raku dos2unix.raku | hexdump -C
00000000 31 0a 32 0a 33 0a 34 0a 35 0a |1.2.3.4.5.|
0000000a
上面复制了真实的 Unix 行结尾(0a
每行):
~$ jot -w '%d' 5 | hexdump -C
00000000 31 0a 32 0a 33 0a 34 0a 35 0a |1.2.3.4.5.|
0000000a
如果上面的脚本不起作用,那么正则表达式解决方案可能对slurp
ed 文件有帮助(\v
代表垂直空白)。 Raku 声称尊重 Raku Regex 方言中行边界的 Unicode 定义: https://unicode.org/reports/tr18/#Line_Boundaries。
~$ raku -e 'slurp.subst(:global, / \v /, "\n").chop.put;' file
#OR
~$ raku -e 'slurp.subst(:global, / <+ :Zl + :Zp> /, "\n").chop.put;' file
请参阅下面的第一个链接的脚本unix2dos.raku
(即相反的答案)。
参考:
https://unix.stackexchange.com/a/743445/227738
https://docs.raku.org/language/newline.html
https://raku.org