[英]Finding All Characters Between Parentheses with a .NET Regex
我需要获取 '(' 和 ')' 字符之间的所有字符。
var str = "dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee) )";
在这个例子中,我需要得到 3 个字符串:
(aaa.bbb)
(c)
( ,ddd (eee) )
我必须写什么模式? 请帮忙。
尝试这样的事情:
\\(([^)]+)\\)
编辑:实际上这对最后一位非常有效 - 这个表达式没有正确捕获最后一个子字符串。 我有 CW 这个答案,以便有更多时间的人可以充实它以使其正常工作。
.NET 支持使用平衡组在正则表达式中递归。 例如,参见http://blog.stevenlevithan.com/archives/balancing-groups
强烈推荐掌握正则表达式
您想使用 .net 正则表达式的平衡匹配组功能。
var s = "dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee) )";
var exp = "\([^()]*((?<paren>\()[^()]*|(?<close-paren>\))[^()]*)*(?(paren)(?!))\)";
var matches = Regex.Matches(s,exp);
您要么需要词法分析器/解析器组合,要么使用具有堆栈支持的词法分析器。 但是正则表达式本身不会让你无处可去。
你需要递归来做到这一点。
Perl 示例:
#!/usr/bin/perl
$re = qr /
( # start capture buffer 1
\( # match an opening paren
( # capture buffer 2
(?: # match one of:
(?> # don't backtrack over the inside of this group
[^()]+ # one or more
) # end non backtracking group
| # ... or ...
(?1) # recurse to opening 1 and try it again
)* # 0 or more times.
) # end of buffer 2
\) # match a closing paren
) # end capture buffer one
/x;
sub strip {
my ($str) = @_;
while ($str=~/$re/g) {
$match=$1; $striped=$2;
print "$match\n";
strip($striped) if $striped=~/\(/;
return $striped;
}
}
$str="dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee) )";
print "\n\nstart=$str\n";
while ($str=~/$re/g) {
strip($1) ;
}
输出:
start=dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee) )
(aaa.bbb)
(c)
( ,ddd (eee) )
(eee)
不是说这比 Regex 好,但这是另一种选择
public static IEnumerable<string> InParen(string s)
{
int count = 0;
StringBuilder sb = new StringBuilder();
foreach (char c in s)
{
switch (c)
{
case '(':
count++;
sb.Append(c);
break;
case ')':
count--;
sb.Append(c);
if (count == 0)
{
yield return sb.ToString();
sb = new StringBuilder();
}
break;
default:
if (count > 0)
sb.Append(c);
break;
}
}
}
如果您只需要处理单层嵌套,您可以使用一对互斥模式。
(\([^()]*\))
(\([^()]*\([^()]*\)[^()]*\))
或者您可以跳过正则表达式,直接解析字符串。 在 (, decrement on ) 上增加一个状态变量,当它归零时打印一行。
正如其他人已经提到的:正则表达式不太适合这样的任务。 但是,如果您的括号没有超过固定数量的嵌套,您可以这样做,但是如果嵌套可以是 3 个或更多,则正则表达式将变得难以编写(和维护!)。 看一看匹配括号中最多一个嵌套括号的正则表达式:
\((?:[^()]|\([^)]*\))*\)
意思是:
\( # match the character '('
(?: # start non-capture group 1
[^()] # match any character not from the set {'(', ')'}
| # OR
\( # match the character '('
[^)]* # match any character not from the set {')'} and repeat it zero or more times
\) # match the character ')'
)* # end non-capture group 1 and repeat it zero or more times
\) # match the character ')'
3的版本会让你的眼睛流血! 您可以使用 .NET 的递归正则表达式匹配功能,但我个人不会这样做:在正则表达式中使用递归会导致疯狂! (当然不是真的,但正则表达式很难理解并将递归混合到混合中,并没有让它更清晰 IMO)
我只是写了一个可能看起来像这个 Python 代码片段的小方法:
def find_parens(str):
matches = []
parens = 0
start_index = -1
index = 0
for char in str:
if char == '(':
parens = parens+1
if start_index == -1:
start_index = index
if char == ')':
parens = parens-1
if parens == 0 and start_index > -1:
matches.append(str[start_index:index+1])
start_index = -1
index = index+1
return matches
for m in find_parens("dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee) )"):
print(m)
打印:
(aaa.bbb)
(c)
( ,ddd (eee) )
我不熟悉 C#,但上面的 Python 代码读起来就像伪代码,我认为转换成 C# 并不费力。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.