1

我有一个包含数百个文本文件的文件夹。每个文件都有相同的格式,例如文件名ATextFile1.txt读取

ATextFile1.txt  09 Oct 2013
1
2
3
4
...

我有一个简化的 Perl 脚本,它应该读取文件并在终端窗口中打印出来:

#!/usr/bin/Perl

use warnings;
use strict;

my $fileName = shift(@ARGV);

open(my $INFILE, "<:encoding(UTF-8)", $fileName) || die("Cannot open $fileName: $!.\n");

foreach (<$INFILE>){
   print("$_");  # Uses the newline character from the file
}

当我在由ATextFile1.txt生成 . Mac版文件生成程序,输出如下:

2016tFile1.txt  09 Oct 2013

经过一些测试,它似乎只打印文本的第一行,其中前 4 个字符被 RegEx 中可以表示为/[0-9][0-9]16/. 如果在我的 Perl 脚本中,我将输出语句替换为print("\t$_");,则将以下行打印到 STDOUT:

2016    ATextFile1.txt  09 Oct 2013

这些文件中的每一个都可以使用任何标准文本编辑器正常读取,但由于某种原因,我的 Perl 脚本似乎无法正确读取和写入文件。任何帮助将不胜感激(我希望我很明显错过了一些东西)。提前致谢!

4

1 回答 1

3

请注意,如果您要打印 UTF-8 字符,STDOUT则需要使用

binmode STDOUT, ':encoding(utf8)';

预先。

看起来好像您的 Mac 文件只有 CR 作为行尾。我知道最近版本的 Macintosh 系统使用 LF 作为行尾(与 Linux 相同),但 Mac OS 9 仅使用 CR,而 Windows 使用文件中的两个字符 CR LF,PerlIO 层将其转换为仅 LF当 perl 在 Windows 平台上运行时。

如果文件中没有换行符,那么 Perl 会将整个文件作为一条记录读取,并且打印它会将所有行叠加在一起。

只要文件相对较小,使用相同 Perl 代码读取任一文件格式的最简单方法是读取整个文件并将其拆分为 CR 或 LF。根据输入文件的来源,其他任何东西都需要不同的代码。

试试这个版本的代码。

use strict;
use warnings;

my @contents = do {
  open my $fh, '<:encoding(utf8)', $ARGV[0];
  local $/;
  my $contents = <$fh>;
  split /[\r\n]+/, $contents;
}

print "$_\n" for @contents;

更新

您可能会尝试的一种替代方法是使用该PerlIO::eol模块,该模块提供了一个 PerlIO 层,该层在读取记录时将任何行结尾转换为 LF。我不确定它是否与 UTF-8 配合得很好,但只要在图层之后添加它就可以了。encoding

它不是核心模块,因此您可能需要安装它,但之后程序就变成了

use strict;
use warnings;

open my $fh, '<:encoding(UTF-8):eol(LF)', $ARGV[0];
binmode STDOUT, ':encoding(utf8)';

print while <$fh>;

我已经创建了 Windows、Linux 和 Mac 样式的文本文件,并且该程序在所有这些文件中都可以正常工作,但是我无法检查具有 0x0D 或 0x0A 作为其编码一部分的 UTF-8 字符是否正确传递,所以要小心。

更新 2

在简要考虑了这一点之后,除了这些字符本身之外,当然没有包含 CR 或 LF 的 UTF-8 编码。ASCII 范围之外的所有字符仅包含设置了最高位的字节,因此它们已经结束0x80并且永远不会是0x0Dor 0x0A

于 2013-10-10T00:31:34.163 回答