繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM