【问题标题】:Finding All Characters Between Parentheses with a .NET Regex使用 .NET 正则表达式查找括号之间的所有字符
【发布时间】:2010-04-06 11:42:58
【问题描述】:

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

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

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

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

我必须写什么模式?请帮忙。

【问题讨论】:

  • 嵌套模式?这是不规则的。
  • 好的。如果 str 是“dfgdgdfg (aaa.bbb) sfd (c) fdsdfg” 什么是获取大括号中所有字符的模式? :)
  • @KennyTM:呵呵,他们什么时候才能学会!
  • @leppie .Net 正则表达式可以处理嵌套模式!所以这是可以做到的。请参阅下面的答案。

标签: c# .net regex


【解决方案1】:

试试这样的:

\(([^)]+)\)

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

【讨论】:

    【解决方案2】:

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

    Mastering Regular Expressions 强烈推荐

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        您要么需要词法分析器/解析器组合,要么使用支持堆栈的词法分析器。但是正则表达式本身不会让你无处可去。

        【讨论】:

          【解决方案5】:

          您需要递归来执行此操作。

          一个 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)
          

          【讨论】:

            【解决方案6】:

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

            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# 不会花太多力气。

            【讨论】:

              【解决方案7】:

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

              【讨论】:

                【解决方案8】:

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

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

                或者你可以跳过正则表达式,直接解析字符串。增加一个状态变量 on (, decrement on ),当它返回零时打印一行。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-07-22
                  • 2012-07-03
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多