使用.NET Regex查找括号之间的所有字符

时间:2010-04-06 11:42:58

标签: c# .net regex

我需要在'('和')'字符之间获取所有字符。

   var str = "dfgdgdfg (aaa.bbb) sfd (c) fdsdfg (   ,ddd   (eee) )";

在这个例子中,我需要得到3个字符串:

(aaa.bbb)
(c)
(    ,ddd   (eee) )

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

8 个答案:

答案 0 :(得分:4)

尝试这样的事情:

  

\(([^)]+)\)

编辑:实际上,完全最后一位工作 - 这个表达式没有正确捕获最后一个子字符串。我有CW这个答案,以便有更多时间的人可以充实它,使其正常工作。

答案 1 :(得分:2)

.NET支持使用平衡组在正则表达式中进行递归。例如,请参阅http://blog.stevenlevithan.com/archives/balancing-groups

强烈推荐

Mastering Regular Expressions

答案 2 :(得分:1)

您需要一个词法分析器/解析器组合,或者使用具有堆栈支持的词法分析器。但正确的正则表达式将让你无处可去。

答案 3 :(得分: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)

答案 4 :(得分:1)

不是说这比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;
            }
        }
    }

答案 5 :(得分:1)

您想使用.net正则表达式的平衡匹配组功能。

var s = "dfgdgdfg (aaa.bbb) sfd (c) fdsdfg (   ,ddd   (eee) )";
var exp = "\([^()]*((?<paren>\()[^()]*|(?<close-paren>\))[^()]*)*(?(paren)(?!))\)";
var matches = Regex.Matches(s,exp);

答案 6 :(得分:0)

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

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

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

答案 7 :(得分:0)

正如其他人已经提到的:正则表达式不适合这样的任务。但是,如果您的括号不超过嵌套的固定数量,您可以这样做,但如果嵌套可以是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#我认为。