我需要一个正则表达式来选择两个外括号之间的所有文本.
例: some text(text here(possible text)text(possible text(more text)))end text
结果: (text here(possible text)text(possible text(more text)))
正则表达式是工作的错误工具,因为您正在处理嵌套结构,即递归.
但是有一个简单的算法可以做到这一点,我在前一个问题的答案中对此进行了描述.
你可以使用正则表达式递归:
\(([^()]|(?R))*\)
我想添加这个答案以便快速参考.随意更新.
.NET Regex使用平衡组.
\((?>\((?)|[^()]+|\)(?<-c>))*(?(c)(?!))\)
在哪里c
用作深度计数器.
在Regexstorm.com上演示
堆栈溢出:使用RegEx平衡匹配括号
Wes'令人费解的博客:使用.NET正则表达式匹配平衡构造
Greg Reinacker的博客:正则表达式中的嵌套构造
PCRE使用递归模式.
\((?:[^)(]+|(?R))*+\)
在regex101演示 ; 或者没有替换:
\((?:[^)(]*(?R)?)*+\)
在regex101演示 ; 或展开性能:
\([^)(]*+(?:(?R)[^)(]*)*+\)
在regex101演示 ; 粘贴的图案(?R)
代表(?0)
.
的Perl,PHP,记事本++, - [R :perl的= TRUE,Python的:正则表达式包与(?V1)
为Perl行为.
Ruby使用子表达式调用.
使用Ruby 2.0 \g<0>
可以用来调用完整模式.
\((?>[^)(]+|\g<0>)*\)
在Rubular演示 ; Ruby 1.9仅支持捕获组递归:
(\((?>[^)(]+|\g<1>)*\))
Rubular演示 (Ruby 1.9.3以来的原子分组)
JavaScript API :: XRegExp.matchRecursive
XRegExp.matchRecursive(str, '\\(', '\\)', 'g');
JS,Java和其他正则表达式,没有递归,最多可达2级嵌套:
\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)
在regex101演示.需要将更深的嵌套添加到模式中.
要在不平衡的括号上更快地失败,请丢弃+
量词.
Java:使用@jaytea的前向引用有趣的想法.
参考 - 这个正则表达式意味着什么?
rexegg.com - 递归正则表达式
Regular-Expressions.info - 正则表达式递归
[^\(]*(\(.*\))[^\)]*
[^\(]*
匹配字符串开头不是(\(.*\))
左括号的[^\)]*
所有内容,捕获括在括号中的所需子字符串,并匹配字符串末尾不是右括号的所有内容.请注意,此表达式不会尝试匹配括号; 一个简单的解析器(参见dehmann的答案)会更适合它.
(?<=\().*(?=\))
如果要在两个匹配的括号中选择文本,则表示您对正则表达式不满意.这是不可能的(*).
此正则表达式只返回字符串中第一个开头和最后一个右括号之间的文本.
(*)除非您的正则表达式引擎具有平衡组或递归等功能.支持此类功能的引擎数量正在缓慢增长,但它们仍然不常用.
实际上可以使用.NET正则表达式来完成它,但它并不是微不足道的,所以请仔细阅读.
你可以在这里阅读一篇好文章.您还可能需要阅读.NET正则表达式.你可以在这里开始阅读.
<>
使用尖括号是因为它们不需要转义.
正则表达式如下所示:
< [^<>]* ( ( (?<) [^<>]* )+ ( (? >) [^<>]* )+ )* (?(Open)(?!)) >
这个答案解释了为什么正则表达式不是执行此任务的正确工具的理论限制。
正则表达式不能做到这一点。
正则表达式基于称为的计算模型Finite State Automata (FSA)
。顾名思义,a FSA
只能记住当前状态,而没有关于先前状态的信息。
在上图中,S1和S2是两个状态,其中S1是开始步骤和最终步骤。因此,如果我们尝试使用字符串0110
,则转换如下:
0 1 1 0 -> S1 -> S2 -> S2 -> S2 ->S1
在上述步骤中,当我们处于第二个位置时,S2
即在解析01
之后0110
,FSA没有关于前一个输入的信息0
,01
因为它只能记住当前状态和下一个输入符号。
在上述问题中,我们需要知道开括号的编号;这意味着它必须存储在某个地方。但是由于FSAs
不能做到这一点,所以不能编写正则表达式。
但是,可以编写算法来完成此任务。算法通常属于Pushdown Automata (PDA)
。PDA
是的上一级FSA
。PDA有一个额外的堆栈来存储一些其他信息。PDA可用于解决上述问题,因为我们可以push
在堆栈中“打开括号pop
”,并在遇到闭合括号时“”。如果最后堆栈是空的,则打开括号和关闭括号匹配。否则不行。