我尝试过`\[.*\]`,但它会吞掉额外的东西(例如`"[chomps] extra [stuff]"`)。
同样,使用懒惰匹配的相同方法`\[.*?\]`当存在嵌套括号时不起作用(例如`"stops [chomping [too] early]!"`)。
试试这样:
$text = "stop [chomping [too] early] here!";
$text =~ s/\[([^\[\]]|(?0))*]//g;
print($text);
这将会打印:
stop here!
简短的解释:
\[ # match '['
( # start group 1
[^\[\]] # match any char except '[' and ']'
| # OR
(?0) # recursively match group 0 (the entire pattern!)
)* # end group 1 and repeat it zero or more times
] # match ']'
以上正则表达式将被替换为空字符串。
您可以在网上测试它:http://ideone.com/tps8t
如@ridgerunner所提到的,您可以通过使*
和字符类[^\[\]]
匹配一次或更多次并使其具有所有权,甚至通过从第1组中制作非捕获组来更有效地创建正则表达式:
\[(?:[^\[\]]++|(?0))*+]
然而,只有在处理大字符串时才能真正提高速度(当然,您可以进行测试!)。
\[([^\[\]]++|(?0))*]
- ridgerunnerGreta:
http://easyethical.org/opensource/spider/regexp%20c++/greta2.htm#_Toc39890907
和
PCRE
http://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions
请参考“递归模式”,其中有一个括号的示例。\[(?R)*\]
编辑:
既然您提到使用Perl,这里有一篇专门介绍如何在Perl中匹配平衡的操作符对的页面:
http://perldoc.perl.org/perlfaq6.html#Can-I-use-Perl-regular-expressions-to-match-balanced-text%3f
类似于:
$string =~ m/(\[(?:[^\[\]]++|(?1))*\])/xg;
由于您正在使用Perl,因此可以使用来自CPAN的模块,而不必编写自己的正则表达式。请查看Text::Balanced
模块,该模块允许您从平衡的定界符中提取文本。使用此模块意味着如果您的定界符突然更改为{}
,您不必想办法修改复杂的正则表达式,您只需要在一个函数调用中更改定界符参数即可。
如果你只关心删除内容而不是捕获它们以便在其他地方使用,那么你可以使用从嵌套组的内部到外部重复移除的方法。
my $string = "stops [chomping [too] early]!";
# remove any [...] sequence that doesn't contain a [...] inside it
# and keep doing it until there are no [...] sequences to remove
1 while $string =~ s/\[[^\[\]]*\]//g;
print $string;
< p > 1 while
会在条件为真时什么都不做。如果一个 s///
匹配并删除一个括号内的部分,则循环将被重复执行,并且 s///
将再次运行。
即使您使用较旧版本的Perl或其他不支持Bart Kiers答案中的 (?0)
递归扩展模式的语言,这也有效。
你想要删除只有在[]之间但不是[]本身的内容。例如:
\[[^\]]*\]
这是一个相当混乱的[]s;-)
它无法处理多个嵌套的[]s。也就是说,匹配[foo [bar] baz]将不起作用。