使用.NET正则表达式查找括号内的所有字符

3
我需要获取圆括号 '(' 和 ')' 之间的所有字符。
   var str = "dfgdgdfg (aaa.bbb) sfd (c) fdsdfg (   ,ddd   (eee) )";

在这个例子中,我需要获取3个字符串:
(aaa.bbb)
(c)
(    ,ddd   (eee) )

我需要写什么样的模式?请帮忙。

5
嵌套模式?那不规则。 - kennytm
如果str是"dfgdgdfg (aaa.bbb) sfd (c) fdsdfg",那么获取所有括号内字符的模式是什么? :) - Laritari
@KennyTM:呵呵,他们什么时候才能学会啊! - leppie
@leppie .Net正则表达式可以处理嵌套模式!因此,这是可以实现的。请参见下面的我的答案。 - Jake
8个回答

4
尝试这样做:

\(([^)]+)\)

编辑:实际上,这对于最后一个部分确实有效 - 这个表达式无法正确捕获最后一个子字符串。我将此答案标记为 CW,以便有更多时间的人可以拓展使其正常工作。

2
您希望使用.NET正则表达式的平衡匹配组功能。
var s = "dfgdgdfg (aaa.bbb) sfd (c) fdsdfg (   ,ddd   (eee) )";
var exp = "\([^()]*((?<paren>\()[^()]*|(?<close-paren>\))[^()]*)*(?(paren)(?!))\)";
var matches = Regex.Matches(s,exp);

2

1

你需要使用递归来完成这个任务。

以下是一个 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)

1

就像其他人已经提到的那样:正则表达式不适合这样的任务。然而,如果您的括号不超过固定数量的嵌套,您可以这样做,但是如果嵌套可以是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的递归正则表达式匹配功能,但我个人不会这样做:在正则表达式中添加递归会导致混乱!(当然并不是真的,但正则表达式已经足够难以理解了,再加上递归,就更加不清晰了)

我只会写一个小方法,可能看起来像这个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#应该不需要太多的努力。


1

不是说这比正则表达式更好,但这是另一个选择

    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;
            }
        }
    }

1
你需要使用词法分析器/语法分析器组合,或者使用支持栈的词法分析器。但是仅靠正则表达式还不够。

0

如果您只需要处理单层嵌套,可以使用一对互斥的模式。

(\([^()]*\))
(\([^()]*\([^()]*\)[^()]*\))

或者您可以跳过正则表达式,直接解析字符串。在 ( 上增加一个状态变量,在 ) 上减少,并在返回零时打印一行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接