C# 使用正则表达式从此字符串获取字符串模式

C# 使用正则表达式从此字符串获取字符串模式,c#,.net,regex,C#,.net,Regex,我的C#应用程序中有一个字符串,如下所示 Sum() 有没有办法像使用C#Regex方法的求和(3,5,4),除法(4,5,5),减法(7,8,9)和乘法()那样分别得到每一个值 Sum、Division、Substract和Multiply都是常量关键字。如果在向方法传递参数时不使用其他方法调用,则是。(如Sum(2,Sum(3,2),4)) 在这种情况下,您可以使用以下模式: ^\w+\(.*)$然后获取组1(它是(.*)组),这些组是参数(求和(3,5,4),除法(4,5,5),减法(7,

我的C#应用程序中有一个字符串,如下所示

Sum()

有没有办法像使用C#Regex方法的求和(3,5,4)
除法(4,5,5)
减法(7,8,9)
乘法()
那样分别得到每一个值


Sum
Division
Substract
Multiply
都是常量关键字。

如果在向方法传递参数时不使用其他方法调用,则是。
(如
Sum(2,Sum(3,2),4)

在这种情况下,您可以使用以下模式:
^\w+\(.*)$
然后获取组1(它是(.*)组),这些组是参数(
求和(3,5,4),除法(4,5,5),减法(7,8,9)
),然后对getted组使用此模式查找所有参数:
\w+\(.*\)


如果您的乘法方法可能有另一个嵌套方法,则regexp无法帮助您。在这种情况下,您应该计算大括号,以查看哪个大括号是关闭的

如果嵌套任意深,您应该使用类似于
regexp.Matches()
regexp.Replace()
的方法迭代执行此操作

复制整个字符串。使用
([a-zA-Z]+\([0-9,]*\)(,)?
作为正则表达式。这将匹配所有最低级别的函数调用——调用图的所有叶节点


调用
Regexp.Matches
提取所有匹配项,调用
Regexp.Replace
从字符串副本中删除所有匹配项。这将除去调用图的所有叶节点。再次调用
Matches()
Replace()
,以消除下一级调用,并不断重复,直到字符串副本为空。

您无法使用RegExp进行任意嵌套-由于RegExp模型的限制,即使在理论上也不可能

在这种情况下,您需要的是一个解析器。手动构建一个非常简单的解析器并不需要很多工作,但是一旦复杂性变得相当大,您应该切换到解析器生成器。我个人最喜欢的是,但是你有很多其他选择。

C#应该能够通过正则表达式中的递归来实现平衡文本。唯一的问题是我认为它保留了外部匹配作为一个整体。要进一步解析内部内容(括号之间),需要一个递归函数调用,每次都要提取标记

我同意@dasblinkenlight关于需要一个像样的解析器的观点。正如他所说,复杂性可能很快变得相当大

下面的正则表达式来自Perl,但对于.Net黑客攻击,其构造应该相同。
如您所见,正则表达式就像一个seive,它遵循一般形式,但是
数学标记之间只处理逗号和数字,允许其余部分通过

但是,如果这是你唯一关心的事情,那么它应该起作用。您会注意到,即使可以将其解析为数据结构(如下所示),以内部方式使用该结构仍需要对数据结构进行另一次递归“解析”(尽管更容易)。如果出于显示或统计目的,则这不是问题

扩展正则表达式:

 {
    (                                      #1 - Recursion group 1                            
      \b(\w+)\s*                                #2 - Math token
      \(                                        #  - Open parenth                   
         (                                        #3 - Capture between parenth's
           (?:  (?> (?: (?!\b\w+\s*\(|\)) . )+ )     # - Get all up to next math token or close parenth
              | (?1)                                 # - OR, recurse group 1
           )*                                        # - Optionally do many times 
         )                                        # - End capture 3
      \)                                        # - Close parenth
    )                                      # - End recursion group 1
    \s*(\,?)                               #4 - Capture optional comma ','

  |                                    # OR,
                                       # (Here, it is only getting comma and digits, ignoring the rest.
                                       #  Comma's  ',' are escaped to make them standout)
    \s*                                       
    (?|                                    # - Start branch reset
        (\d+)\s*(\,?)                          #5,6 - Digits then optional comma ','
      | (?<=\,)()\s*(\,|\s*$)                  #5,6 - Comma behind. No digit then, comma or end
    )                                      # - End branch reset
 }xs;   # Options: expanded, single-line

你打算把它们再安顿一点吗?比如说,
乘法(乘法(1,2),乘法(3,4)),乘法(5,6))
也需要嵌套。这可能吗?我下面的解决方案处理嵌套。因为嵌套是必需的,所以您不能通过一个简单的Regex方法调用来完成,您必须使用for循环。这应该没什么大不了的。从
\w+\(\d,)+\)
开始,在字符串处传递,用根据传递的内容计算的答案替换找到的每个匹配项。您将不断重复此操作,直到字符串中剩下的最后一项是答案。
 {
    (                                      #1 - Recursion group 1                            
      \b(\w+)\s*                                #2 - Math token
      \(                                        #  - Open parenth                   
         (                                        #3 - Capture between parenth's
           (?:  (?> (?: (?!\b\w+\s*\(|\)) . )+ )     # - Get all up to next math token or close parenth
              | (?1)                                 # - OR, recurse group 1
           )*                                        # - Optionally do many times 
         )                                        # - End capture 3
      \)                                        # - Close parenth
    )                                      # - End recursion group 1
    \s*(\,?)                               #4 - Capture optional comma ','

  |                                    # OR,
                                       # (Here, it is only getting comma and digits, ignoring the rest.
                                       #  Comma's  ',' are escaped to make them standout)
    \s*                                       
    (?|                                    # - Start branch reset
        (\d+)\s*(\,?)                          #5,6 - Digits then optional comma ','
      | (?<=\,)()\s*(\,|\s*$)                  #5,6 - Comma behind. No digit then, comma or end
    )                                      # - End branch reset
 }xs;   # Options: expanded, single-line
 use Data::Dumper;


#//
 my $regex = qr{(\b(\w+)\s*\(((?:(?>(?:(?!\b\w+\s*\(|\)).)+)|(?1))*)\))\s*(\,?)|\s*(?|(\d+)\s*(\,?)|(?<=\,)()\s*(\,|\s*$))}s;


#//
 my $sample = ', asdf Multiply(9, 4, 3, hello,  _Sum(3,5,4,) , Division(4, Sum(3,5,4), 5), ,, Subtract(7,8,9))';

 print_math_toks( 0, $sample );

 my @array;
 store_math_toks( 0, $sample, \@array );
 print Dumper(\@array);


#//
 sub print_math_toks
 {
    my ($cnt, $segment) = @_;
    while ($segment  =~ /$regex/g )
    {
      if (defined $5) {
         next if $cnt < 1;
         print "\t"x($cnt+1), "$5$6\n";
      }
      else {
         ++$cnt;
         print "\t"x$cnt, "$2(\n";
         my $post = $4;

         $cnt = print_math_toks( $cnt, $3 );

         print "\t"x$cnt, ")$post\n";
         --$cnt;
      }
    }
    return $cnt;
 }


 sub store_math_toks
 {
    my ($cnt, $segment, $ary) = @_;
    while ($segment  =~ /$regex/g )
    {
      if (defined $5) {
         next if $cnt < 1;
         if (length $5) {
            push (@$ary, $5);
         }
         else {
            push (@$ary, '');
         }
      }
      else {
         ++$cnt;
         my %hash;
         $hash{$2} = [];
         push (@$ary, \%hash);

         $cnt = store_math_toks( $cnt, $3, $hash{$2} );

         --$cnt;
      }
    }
    return $cnt;
 }
        Multiply(
                9,
                4,
                3,
                _Sum(
                        3,
                        5,
                        4,

                ),
                Division(
                        4,
                        Sum(
                                3,
                                5,
                                4
                        ),
                        5
                ),
                ,
                ,
                Subtract(
                        7,
                        8,
                        9
                )
        )
$VAR1 = [
          {
            'Multiply' => [
                            '9',
                            '4',
                            '3',
                            {
                              '_Sum' => [
                                          '3',
                                          '5',
                                          '4',
                                          ''
                                        ]
                            },
                            {
                              'Division' => [
                                              '4',
                                              {
                                                'Sum' => [
                                                           '3',
                                                           '5',
                                                           '4'
                                                         ]
                                              },
                                              '5'
                                            ]
                            },
                            '',
                            '',
                            {
                              'Subtract' => [
                                              '7',
                                              '8',
                                              '9'
                                            ]
                            }
                          ]
          }
        ];