匹配 perl 正则表达式中括号和方括号外的所有逗号

match all commas that are outside parentheses and square brackets in perl regex

我正在尝试使用正则表达式匹配所有逗号(后跟 space):, 在任何括号或方括号之外,即逗号不应包含在圆括号或方括号。

目标字符串是A, An(hi, world[hello, (hi , world) world]); This, These。在这种情况下,它应该匹配第一个逗号和最后一个逗号(AAnthisthese 之间的逗号)。

所以我可以将 A, An(hi, world[hello, (hi , world) world]); This, These 拆分为 AAn(hi, world[hello, (hi , world) world]); ThisThese,而不会使 parens/brackets 不平衡。

为此,似乎很难单独使用正则表达式。有没有其他方法可以解决这个问题?

我使用的正则表达式: , (?![^()\[\]]*[\)\]])

但是这个表达式会匹配其他额外的两个逗号, (第二个和第三个)不应该被匹配。

虽然如果它匹配以下字符串,它将匹配正确的逗号(分别是第一个):A, An(hi, world)A, An[hi, world]

但是如果圆括号和方括号互相包含,就会出问题。

此 link 中的更多详细信息: https://regex101.com/r/g8DOh6/1

检查逗号 , 是否在 brackets/parenthesis 内,例如

[(,),],[abc,(def,[ghi,],),],[(,),]
      ^                    ^

意味着模式必须知道这些 brackets/parenthesis 中的每一个何时以平衡的方式打开和关闭,所以不仅仅是 [([],因为它应该是 [([])]

这是一个替代解决方案,它不能直接解决您的问题,但可能更接近一步。

  1. 符合以下任一条件:

    一个。逗号

    b。包含在外部 []() 中的组。参见 Regular expression to match balanced parentheses

  2. 过滤掉1.b

正则表达式模式:

(?:\((?>[^()]|(?R))*\)|\[(?>[^\[\]]|(?R))*\]|,)

对于这个字符串,匹配如下所示:

A, An(hi, world[hello, (hi , world) world]) and this, is that, for [the, one (in, here, [is not,])] and last,here!
 ^   ^------------------------------------^         ^        ^     ^------------------------------^         ^
  • 所以它没有捕获任何 bracket/parenthesis 组中的任何逗号,因为它捕获了它们作为一个整体。现在,您在外层有了逗号。

这里的问题是在这种情况下识别 parenthesis/brackets 的“平衡”对。这是一个公认的问题,有图书馆。他们可以找到顶级匹配对,(...)/[...] 里面的所有内容,以及括号外的所有其他内容——然后处理“else.”

一种方法,使用 Regexp::Common

use warnings;
use strict;
use feature 'say';

use Regexp::Common;

my $str = shift // q{A, t(a,b(c,))u B, C, p(d,)q D,}; 

my @all_parts = split /$RE{balanced}{-parens=>'()[]'}/, $str;

my @no_paren_parts = grep { not /\(.*\) | \[.*\]/x } @all_parts;

say for @no_paren_parts;

这使用了 split's property to return the list with separators included when the regex in the separator pattern captures. The library regex 捕获,所以我们得到了全部 - 通过将字符串拆分为正则表达式匹配的部分以及正则表达式匹配的部分。分隔符包含成对的定界符,而其他术语不能通过构造,因此我通过它过滤掉它们。 打印

A, t
u B, C, p
q D,

paren/bracket 项消失了,但字符串的拆分方式有点随意。

以上内容有些“通用”,仅使用库来提取平衡对 ()/[],以及字符串的所有其他部分。或者,我们可以从字符串

中删除这些模式
$str =~ s/$RE{balanced}{-parens=>'()[]'}//g;

一起

A, tu B, C, pq D,

现在可以简单地用逗号分隔

my @terms = split /\s*,\s*/, $str;
say for @terms;

A
tu B
C
pq D

在这种情况下,这是期望的结果,如评论中所述。

另一个最著名的库是核心 Text::Balance,在很多方面都更为基础。有关示例,请参阅 here, and for example this post and and


一个例子。与

my $str = q(it, is; surely);

my @terms = split /[,;]/, $str;

one在数组@terms中得到itissurely,而with

my @terms = split /([,;])/, $str;

我们得到@terms所有的:it,is;surely


同样通过构造,它包含正则表达式在偶数索引处匹配的内容。所以对于所有其他部分,我们可以在奇数索引处获取元素

my @other_than_matched_parts = @all_parts[ grep { not $_ & 1 } 0..$#all_parts ];

zdim 提到的一种方法是使用核心 Text::Balanced 模块。示范:

#!/usr/bin/env perl
use strict;
use warnings;
use feature qw/say/;
use Text::Balanced qw/extract_bracketed/;

my $str = "A, An(hi, world[hello, (hi , world) world]); This, These";
my ($inside, $after, $before) = extract_bracketed $str, '()[]', qr/[^([]*/;

my @tokens = (split(/,/, $before//""), $inside, split(/,/, $after//""));

# Displays
# A  An (hi, world[hello, (hi , world) world]) ; This  These
say join(' ', @tokens);