不包含在括号中的匹配文本

Matching text not enclosed by parenthesis

我仍在学习 Perl,如果这是一个明显的问题,我深表歉意。 有没有办法匹配没有被括号括起来的文本? 例如,搜索 foo 将只匹配第二行。

(bar foo bar)
bar foo (
bar foo 
   (bar) (foo)
)

正则表达式模式具有隐式前导 \G(?s:.)*? ("skip characters until a match is found")。下面对该定义进行扩展,将嵌套的括号视为要跳过的字符。

while (
   $string =~ m{
      \G (?&MEGA_DOT)*?

      ( foo )

      (?(DEFINE)
         (?<MEGA_DOT> [^()] | \( (?&MEGA_DOT)*+ \) )
      )
   }xg
) {
   say "Found a match at pos $-[1].";
}

这与"obvious"相去甚远;相反。对于复杂的模式,没有直接的方式说 "don't match"(在字符级别有很好的支持,[^a]\S 等)。正则表达式首先是关于匹配事物,而不是关于不匹配它们。

一种方法是匹配那些(可能嵌套的)定界符并获取除此之外的所有内容。

查找嵌套定界符的好工具是核心模块Text::Balanced。当它匹配时,它还可以为我们提供匹配之前的子字符串和匹配之后的字符串的其余部分。

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

use Text::Balanced qw(extract_bracketed);

my $text = <<'END';
(bar foo bar)
bar foo (
bar foo 
   (bar) (foo)
   )
END

my ($match, $before);
my $remainder = $text;
while (1) {
    ($match, $remainder, $before) = extract_bracketed($remainder, '(', '[^(]*');
    print $before // $remainder;
    last if not defined $match; 
}

extract_bracketedreturns匹配,剩余子串($remainder),匹配前子串($before);所以我们在剩余部分继续匹配。

摘自 , where there are more details and another way, using Regexp::Common.