我正在用Perl编写一些解析器,这里有一个split问题。这是我的代码:
my $str = 'a,b,"c,d",e';
my @arr = split(/,(?=([^"]*"[^"]*")*[^"]*$)/, $str);
# try to split the string by comma delimiter, but only if comma is followed by the even or zero number of quotes
foreach my $val (@arr) {
print "$valn"
}
我期待以下内容:
a
b
"c,d"
e
但这才是我真正收到的:
a
b,"c,d"
b
"c,d"
"c,d"
e
我看到我的字符串部分在数组中,它们的索引是0、2、4、6。但是,如何避免在生成的数组中出现这些奇怪的b,"c,d"
和其他剩余字符串部分呢?我的regexp分隔符中有错误吗?或者有一些特殊的split
选项吗?
您需要使用一个非捕获组:
my @arr = split(/,(?=(?:[^"]*"[^"]*")*[^"]*$)/, $str);
^^
查看IDEONE演示
否则,捕获的文本将作为结果数组的一部分输出。
参见perldoc参考:
如果正则表达式具有分组,则生成的列表包含分组中匹配的子字符串以及
split
中的一个功能让您感到困惑,因为如果您正在使用一个组,并且它被设置为捕获-它也会返回捕获的"位"。
但是,与其使用split
,我建议使用Text::CSV
模块,它已经为您处理了报价:
#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new();
my $fields = $csv->getline( *DATA );
print join "n", @$fields;
__DATA__
a,b,"c,d",e
打印:
a
b
c,d
e
我的推理相当简单——你正在进行引号匹配,可能会有引号/转义引号等。这意味着你正在尝试进行递归解析,而regex
根本不适合这样做。
如果您对regex:没有真正的限制,则可以使用Text::ParseWords的parse_line()
use Text::ParseWords;
my $str = 'a,b,"c,d",e';
my @arr = parse_line(',', 1, $str);
foreach (@arr)
{
print "$_n";
}
输出:
a
b
"c,d"
e
进行匹配而不是拆分。
use strict; use warnings;
my $str = 'a,b,"c,d",e';
my @matches = $str =~ /"[^"]*"|[^,]+/g;
foreach my $val (@matches) {
print "$valn"
}