我需要一个正则表达式来选择两个外括号之间的所有文本。
例子: START_TEXT(这里的文本(可能的文本)文本(可能的文本(更多的文本))END_TXT ^ ^
结果: (此处文本(可能的文本)文本(可能的文本(更多的文本)))
我需要一个正则表达式来选择两个外括号之间的所有文本。
例子: START_TEXT(这里的文本(可能的文本)文本(可能的文本(更多的文本))END_TXT ^ ^
结果: (此处文本(可能的文本)文本(可能的文本(更多的文本)))
当前回答
这是最终的正则表达式:
\(
(?<arguments>
(
([^\(\)']*) |
(\([^\(\)']*\)) |
'(.*?)'
)*
)
\)
例子:
input: ( arg1, arg2, arg3, (arg4), '(pip' )
output: arg1, arg2, arg3, (arg4), '(pip'
注意,'(pip'被正确地管理为字符串。 (在调节器试过:http://sourceforge.net/projects/regulator/)
其他回答
这个答案解释了为什么正则表达式不是这项任务的正确工具的理论局限性。
正则表达式不能做到这一点。
正则表达式基于有限状态自动机(FSA)的计算模型。顾名思义,FSA只能记住当前状态,它没有关于以前状态的信息。
在上图中,S1和S2是两种状态,其中S1是开始和结束步骤。因此,如果我们尝试使用字符串0110,转换如下:
0 1 1 0
-> S1 -> S2 -> S2 -> S2 ->S1
在上述步骤中,当我们在第二个S2,即解析完0110的01之后,FSA没有关于01中前一个0的信息,因为它只能记住当前状态和下一个输入符号。
在上面的问题中,我们需要知道左括号的no;这意味着它必须存储在某个地方。但是由于fsa不能这样做,因此不能编写正则表达式。
但是,可以编写一个算法来完成这项任务。算法一般属于下推自动机(PDA)。PDA比FSA高一级。PDA有一个额外的堆栈来存储一些额外的信息。pda可以用来解决上述问题,因为我们可以在堆栈中“推入”开括号,并在遇到闭括号时“弹出”它们。如果在结束时,堆栈为空,则开始括号和结束括号匹配。否则不。
正则表达式是一个错误的工具,因为你正在处理嵌套结构,即递归。
但是有一个简单的算法可以做到这一点,我在之前的问题的回答中详细描述了它。其要点是编写代码扫描字符串,并对尚未与闭括号匹配的开括号保持计数器。当计数器返回0时,您就知道已经到达了最后的右括号。
我写了一个叫做balanced的JavaScript库来帮助完成这个任务。你可以这样做
balanced.matches({
source: source,
open: '(',
close: ')'
});
你甚至可以做替换:
balanced.replacements({
source: source,
open: '(',
close: ')',
replace: function (source, head, tail) {
return head + source + tail;
}
});
下面是一个更复杂的交互式示例JSFiddle。
除了bobble bubble的答案之外,还有其他类型的正则表达式支持递归结构。
Lua
使用%b() (%b{} / %b[]作为大括号/方括号):
对于字符串中的s。gmatch(“提取(a (b) c)和f (g)) ((d)”,“% b()”)做打印(s)结束(见演示)
Raku(前Perl6):
不重叠的多个平衡括号匹配:
my regex paren_any { '(' ~ ')' [ <-[()]>+ || <&paren_any> ]* }
say "Extract (a(b)c) and ((d)f(g))" ~~ m:g/<&paren_any>/;
# => (「(a(b)c)」 「((d)f(g))」)
重叠多个平衡括号匹配:
say "Extract (a(b)c) and ((d)f(g))" ~~ m:ov:g/<&paren_any>/;
# => (「(a(b)c)」 「(b)」 「((d)f(g))」 「(d)」 「(g)」)
看到演示。
Python的非正则表达式解决方案
参见poke对如何在平衡括号之间获取表达式的回答。
Java可定制的非正则表达式解决方案
下面是一个可定制的解决方案,允许在Java中使用单个字符文字分隔符:
public static List<String> getBalancedSubstrings(String s, Character markStart,
Character markEnd, Boolean includeMarkers)
{
List<String> subTreeList = new ArrayList<String>();
int level = 0;
int lastOpenDelimiter = -1;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == markStart) {
level++;
if (level == 1) {
lastOpenDelimiter = (includeMarkers ? i : i + 1);
}
}
else if (c == markEnd) {
if (level == 1) {
subTreeList.add(s.substring(lastOpenDelimiter, (includeMarkers ? i + 1 : i)));
}
if (level > 0) level--;
}
}
return subTreeList;
}
}
示例用法:
String s = "some text(text here(possible text)text(possible text(more text)))end text";
List<String> balanced = getBalancedSubstrings(s, '(', ')', true);
System.out.println("Balanced substrings:\n" + balanced);
// => [(text here(possible text)text(possible text(more text)))]
我没有使用正则表达式,因为它很难处理嵌套代码。因此,这个代码片段应该能够允许你抓取带有平衡括号的代码段:
def extract_code(data):
""" returns an array of code snippets from a string (data)"""
start_pos = None
end_pos = None
count_open = 0
count_close = 0
code_snippets = []
for i,v in enumerate(data):
if v =='{':
count_open+=1
if not start_pos:
start_pos= i
if v=='}':
count_close +=1
if count_open == count_close and not end_pos:
end_pos = i+1
if start_pos and end_pos:
code_snippets.append((start_pos,end_pos))
start_pos = None
end_pos = None
return code_snippets
我使用它从文本文件中提取代码片段。