我有一个文件,每行包含字符串,如下所示
"229269_2,190594_2,94552_2,266076_2,269628_2,165328_2,99319_2,263339_2,263300_2,99315_2,271509_2,2714",A,1
下一行可能看起来像
84545,X,2
我正在尝试在Perl中解析此文本。注意:当行中有多个引号时,引号存在于字符串中,但如果只有item,则不存在引号 我想将每个项目解析成一个数组。我尝试了以下正则表达式
@fields = ($_ =~ /(\d+\_\d+),*/g);
但缺少最后一个2714
。如何捕获边缘情况?任何帮助赞赏。提前致谢
答案 0 :(得分:1)
看起来您有一个CSV文件,因此请使用实际的CSV解析器,例如Text::CSV
。
解析列后,您可以将第一个字段分隔到数组中:
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new ( { binary => 1 } ) # should set binary attribute.
or die "Cannot use CSV: ".Text::CSV->error_diag ();
my $line = qq{"229269_2,190594_2,94552_2,266076_2,269628_2,165328_2,99319_2,263339_2,263300_2,99315_2,271509_2,2714",A,1 the next line could look like 84545,X,2};
if ($csv->parse($line)) {
my @columns = $csv->fields();
my @nums = split ',', $columns[0];
print "@nums\n";
}
输出:
229269_2 190594_2 94552_2 266076_2 269628_2 165328_2 99319_2 263339_2 263300_2 99315_2 271509_2 2714
是的,当然几乎可以使用正则表达式。但您需要了解的是,这会使您的代码非常脆弱且难以维护。
即使你想使用正则表达式,你仍然应该分两步完成。首先分离CSV的初始列,然后处理您担心的特定列。
因为您只是使用第一列,所以可以使用以下代码:
use strict;
use warnings;
my $line = qq{"229269_2,190594_2,94552_2,266076_2,269628_2,165328_2,99319_2,263339_2,263300_2,99315_2,271509_2,2714",A,1 the next line could look like 84545,X,2};
if ($line =~ /^"(.*?)"|^([^,]*)/) {
my $column0 = $1 // $2;
my @nums = split ',', $column0;
print "@nums\n";
}
上述情况恰好与之前的代码完成相同的事情。然而,它有一个很大的缺陷,对于维护程序员而言,这种情况并不那么明显。
每当一个新的编码人员,甚至是你自己在6个月内查看第一组代码时,您的数据格式就非常明显。您正在使用CSV文件,第一列是一个分隔的列表用逗号。第二个代码也可以工作,但是新的维护者必须真正阅读正则表达式,并弄清楚是什么在理解数据的格式,以及代码是否实际上正确地执行了。
无论如何,尽你所能,但我强烈建议你使用实际的CSV Parser来解析csv文件。
答案 1 :(得分:0)
如果您想要的只是最后两个字段......
my $string = qq("229269_2,190594_2,94552_2,266076_2,269628_2,165328_2,99319_2,263339_2,263300_2,99315_2,271509_2,2714",A,1);
$string =~ s/"//g; # delete the quotes
my @f = split (/,/, $string); # split on the comma
pop @f; pop @f; # jettison the last two columns
# @f contains what you're looking for