我想编写一个匹配
之间的正则表达式()
(())
(()())
((()))
()()()
等
答案 0 :(得分:21)
所有这些答案声称你不能使用模式来匹配具有平衡嵌套parens的字符串是非常错误的。假装现代编程语言匹配的模式仅限于病理教科书意义上的“常规语言”是不切实际的。一旦你允许反向引用,它们就不会。这使得真实世界的模式比教科书版本更匹配,使它们更加实用。
匹配平衡parens的最简单模式是\((?:[^()]*+|(?0))*\)
。但是你应该从不写那个,因为它太紧凑而不易读。您应该始终以/x
模式编写它以允许空格和注释。所以这样写:
m{
\( # literal open paren
(?: # begin alternation group
[^()]*+ # match nonparens possessively
| # or else
(?0) # recursively match entire pattern
)* # repeat alternation group
\) # literal close paren
}x
对于命名抽象,并将其定义及其排序与执行分离,还有很多要说的。这导致了这种情况:
my $nested_paren_rx = qr{
(?&nested_parens)
(?(DEFINE)
(?<open> \( )
(?<close> \) )
(?<nonparens> [^()] )
(?<nested_parens>
(?&open)
(?:
(?&nonparens) *+
|
(?&nested_parens)
) *
(?&close)
)
)
}x;
第二种形式现在可以包含在更大的模式中。
不要让任何人告诉你不能使用模式来匹配递归定义的东西。正如我刚才所说,你当然可以。
当你在它的时候,确保永远不要写线噪声模式。你不必,你不应该。没有编程语言可以维护,禁止使用空格,注释,子例程或字母数字标识符。所以在你的模式中使用所有这些东西。
当然,它 帮助为这种工作选择正确的语言。 ☺
答案 1 :(得分:5)
如果您遇到正则表达式语法不支持递归匹配的语言,我会给您简单的Javascript实现,您应该可以使用您选择的语言创建自己的语言:
function testBraces(s) {
for (var i=0, j=0; i<s.length && j>=0; i++)
switch(s.charAt(i)) {
case '(': { j++ ; break; }
case ')': { j-- ; break; }
}
return j == 0;
}
在这里你可以玩它:http://jsfiddle.net/BFsn2/
答案 2 :(得分:4)
正则表达式无法有效处理这种嵌套结构。你需要的是语法和语法解析器。在你的情况下,语法很简单。如果您正在使用python尝试pyparsing或funcparserlib。
通过pyparsing,您可以执行以下操作:
from pyparsing import nestedExpr
nestedExpr().parseString( "(some (string you) (want) (to) test)" ).asList()
这将返回一个包含嵌套字符串的已解析组件的列表。 nestedExpr的默认分隔符是括号,因此您不必执行任何额外操作。如果您想使用funcpasrerlib,可以尝试以下
from funcparserlib.parser import forward_decl, many, a
bracketed = forward_decl()
bracketed.define(a('(') + many(bracketed) + a(')'))
之后你可以打电话
bracketed.parse( "( (some) ((test) (string) (you) (want)) (to test))" )
它将返回元组中已解析的元素。
答案 3 :(得分:0)