我有一个包含文本的 CSV 文件,其中包含新的换行符。例如
1,b,hello
world,x
2,a,hello
mars,y
要一次连续阅读所有内容,我想为 $/ 特殊变量指定一个正则表达式。关于我如何做到这一点的任何建议?
我的想法是,如果我为我的特殊变量输入类似 "(x|y)\n" 的内容,它应该捕获行以 x 或 y 以及新行结尾的情况。
谢谢
我有一个包含文本的 CSV 文件,其中包含新的换行符。例如
1,b,hello
world,x
2,a,hello
mars,y
要一次连续阅读所有内容,我想为 $/ 特殊变量指定一个正则表达式。关于我如何做到这一点的任何建议?
我的想法是,如果我为我的特殊变量输入类似 "(x|y)\n" 的内容,它应该捕获行以 x 或 y 以及新行结尾的情况。
谢谢
您不能对 $/ 使用正则表达式。但是,如果文件不是太大,您可以将整个内容读入一个标量并在正则表达式上拆分。
@records = split /(x|y)\n/, $data;
没有将这样的文件分成记录的通用方法,因为无法判断文件中的一行是更多当前记录还是新记录的开始。
但是,如果您可以假设
一条记录中总是有相同数量的字段
字段中的数据从不包含逗号
记录的最后一个字段永远不会跨行拆分
然后你可以简单地从文件中累积行,直到你有足够数量的字段
这个程序演示了这个原理。
use strict;
use warnings;
while (my $record= <>) {
$record .= <> until $record =~ tr/,// == 3;
print ">> $record\n";
}
输出
>> 1,b,hello
world,x
>> 2,a,hello
mars,y
您可以创建自己的子程序以一次读取一个数据集:
sub readDataSet {
my $buffer = '';
local $/ = "\n";
$buffer .= <STDIN> until $buffer =~ /(x|y)\n$/;
return $buffer;
}
my $nextRow = readDataSet();
这将返回一整行。我可以这样做,因为您的 Regexp 以恒定部分结尾。这个子有几个变体:
从任何文件句柄读取:
sub readDataSet {
my ($filehandle) = @_;
my $buffer = "";
$buffer .= <$filehandle> until $buffer =~ /(x|y)\n$/;
return $buffer;
}
open my $fh, "<", $filename or die;
my $nextRow = readDataSet($fh);
构造一个匿名子来读取。Filehandle 在构造函数 sub 中只提供一次。这有点面向对象。
sub newDataSetReader {
my ($filehandle) = @_;
return sub {
my $buffer = '';
local $/ = "\n";
$buffer .= <$filehandle> until $buffer =~ /(x|y)\n$/;
return $buffer;
};
}
open my $fh, "<", $filename or die;
my $reader = newDataSetReader($fh);
my $nextRow = $reader->();
我更喜欢最后一种解决方案,但只有从多个文件中读取才有意义。
当您通过 sub 阅读时,您可以轻松插入调试钩子或预过滤数据,例如将行拆分为字段并返回一个数组而不是单个字符串。