假设我有一个字符串:
my $string = "foo{a},bar{b}, baz{c,d,e}";
它使用一组分组字符来区分两个级别:
$grouping_characters = "{}"
我想将此字符串拆分为“外部”逗号 ( ,),以尊重内部的所有内容$grouping_characters。
对于上面的示例,输出应为:
my @result = ("foo{a}", "bar{b}", "baz{c,d,e}")
我如何在 Perl 中做到这一点?
第一:如果您想正确解析某些编程语言或配置格式,您可能需要使用实际的解析器。
但是,您的任务可以通过正则表达式来完成。但是我们不会编写正则表达式来匹配我们想要拆分的逗号。相反,我们编写了一个匹配列表部分的正则表达式:
my $regex = qr/
\w+ # item can begin with some identifier
\{ [^\}]* \} # followed by some stuff in braces
[,;] # must end with comma or semicolon
/x;
然后我们可以提取匹配项
my $string = "foo{a},bar{b}, baz{c,d,e};";
my @result = $string =~ /$regex/g;
dd @result; # using dd from Data::Dump
输出:
("foo{a},", "bar{b},", "baz{c,d,e};")
挺棒的。现在,我们以两种方式改进我们的正则表达式:
一起:
my $delims = quotemeta "{}";
my $regex = qr/
\w+
[$delims] [^$delims]* [$delims]
/x;
my $string = "foo{a},bar{b}, baz{c,d,e};";
my @result = $string =~ /\G ($regex) [,;] \s*/xg;
dd @result;
\G断言锚定在上一场比赛停止的地方。
输出:
("foo{a}", "bar{b}", "baz{c,d,e}")
精彩的。这可以通过两种方式进一步细化:
foo}a{将是一个有效的项目......。如果不需要所有这些,则当前的正则表达式应该可以。
尝试使用这个正则表达式:
(.*[}]),\s*(.*[}]),\s*(.*[{].*[}])
像这样:
my $string = "foo{a},bar{b}, baz{c,d,e}";
print grep(/(.*[}]),\s*(.*[}]),\s*(.*[{].*[}])/, $string);
你可以试试:
my $string = "foo{a},bar{b}, baz{c,d,e}";
print join(",",split(/,\s*(?=\w+{[a-z,]+})/g,$string));
简单的解析器:
#!/usr/bin/perl
use warnings;
use strict;
my $string = 'foo{a},bar{b}, baz{c,d,e}';
my @parts;
my $inside;
my $from = 0;
for my $i (0 .. length $string) {
my $char = substr $string, $i, 1;
if ('{' eq $char) {
$inside++;
} elsif ('}' eq $char) {
$inside--
} elsif (',' eq $char and not $inside) {
push @parts, substr $string, $from, $i - $from;
$from = $i + 1;
}
}
push @parts, substr $string, $from;
print "$_\n" for @parts;
删除空格留给读者作为练习。
> echo "foo{a},bar{b}, baz{c,d,e}" | perl -lne 'push @a,/.*?{.*?},?/g;for(@a){print}'
foo{a},
bar{b},
baz{c,d,e}
>