我在Perl上编写了一些解析器,这是分裂的问题。这是我的代码:
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 "$val\n"
}
我期待以下内容:
a
b
"c,d"
e
但这是我真正收到的:
a
b,"c,d"
b
"c,d"
"c,d"
e
我看到我的字符串部分在数组中,它们的索引是0,2,4,6。但是如何在结果数组中避免这些奇数b,"c,d"
和其他其他字符串部分?我的正则表达式分隔符中是否有任何错误,或者是否有一些特殊的split
选项?
答案 0 :(得分:4)
您需要使用非捕获组:
my @arr = split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, $str);
^^
请参阅IDEONE demo
否则,捕获的文本将作为结果数组的一部分输出。
如果正则表达式具有分组,则生成的列表也包含分组中匹配的子字符串
答案 1 :(得分:4)
绊倒你的是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
根本不适合做的事情。
答案 2 :(得分:2)
如果你没有真正的正则表达式,你可以使用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
答案 3 :(得分:0)
匹配而不是拆分。
use strict; use warnings;
my $str = 'a,b,"c,d",e';
my @matches = $str =~ /"[^"]*"|[^,]+/g;
foreach my $val (@matches) {
print "$val\n"
}