.NET正则表达式不按预期顺序捕获

时间:2010-08-20 20:44:57

标签: .net regex

在.NET中,正则表达式并没有像我期望的那样组织捕获。 (我不会称这是一个错误,因为显然有人打算这样做。但是,我不希望它如何工作,也不会发现它有用。)

这个正则表达式用于配方成分(为了举例简化):

(?<measurement>           # begin group
  \s*                     # optional beginning space or group separator
  (
    (?<integer>\d+)|      # integer
    (
      (?<numtor>\d+)      # numerator
      /
      (?<dentor>[1-9]\d*) # denominator. 0 not allowed
    )
  )
  \s(?<unit>[a-zA-Z]+)
)+                        # end group. can have multiple

我的字符串:3 tbsp 1/2 tsp

结果组和捕获:

  

[测量] [0] = 3汤匙   [测量] [ 1 ] = 1/2茶匙
  [整数] [0] = 3
  [numtor] [ 0 ] = 1
  [dentor] [ 0 ] = 2
  [单位] [0] =汤匙
  [单位] [ 1 ] = TSP

请注意,即使1/2 tsp在第二次捕获中,它的部分位于[0],因为这些斑点以前未使用过。

有没有办法让所有部分都具有可预测的有用索引,而无需再次通过正则表达式重新运行每个组?

3 个答案:

答案 0 :(得分:1)

好像你可能需要循环输入,一次匹配一个测量。然后,在该测量的循环迭代期间,您将可以预测访问该测量的各个部分。

答案 1 :(得分:1)

  

有没有办法让所有部分都具有可预测的有用索引,而无需再次通过正则表达式重新运行每个组?

没有捕获。如果您要进行多个匹配,我建议您删除+并分别匹配度量的每个组成部分,如下所示:

  string s = @"3 tbsp 1/2 tsp";

  Regex r = new Regex(@"\G\s* # anchor to end of previous match
    (?<measurement>           # begin group
      (
        (?<integer>\d+)       # integer
      |
        (
          (?<numtor>\d+)      # numerator
          /
          (?<dentor>[1-9]\d*) # denominator. 0 not allowed
        )
      )
      \s+(?<unit>[a-zA-Z]+)
    )                         # end group.
  ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture);

  foreach (Match m in r.Matches(s))
  {
    for (int i = 1; i < m.Groups.Count; i++)
    {
      Group g = m.Groups[i];
      if (g.Success)
      {
        Console.WriteLine("[{0}] = {1}", r.GroupNameFromNumber(i), g.Value);
      }
    }
    Console.WriteLine("");
  }

输出:

[measurement] = 3 tbsp
[integer] = 3
[unit] = tbsp

[measurement] = 1/2 tsp
[numtor] = 1
[dentor] = 2
[unit] = tsp

开头的\G确保匹配仅在前一个匹配结束时发生(或者如果这是第一次匹配尝试则在输入的开头)。您还可以在调用之间保存匹配结束位置,然后使用双参数Matches方法在同一点继续解析​​(就好像这实际上是输入的开始)。

答案 2 :(得分:-1)

看看这个....这里有一些可能有助于改进正则表达式的建议

(?<measurement>           # begin group
  \s*                     # optional beginning space or group separator
  (
    (?<integer>\d+)\.?|   # integer
    (
      (?<numtor>\d+)      # numerator
      /
      (?<dentor>[1-9]\d*) # denominator. 0 not allowed
    )
  )
  \s(?<unit>[a-zA-Z]+)
)+                        # end group. can have multiple
  • 正则表达式期望在测量标签之后的开始...... ....
  • (?<integer>\d+)我会尝试使用\s?代替\.来捕获空白区域,因为它正在逃离全站,并期望在某个地方出现一个句号。
  • 转义/喜欢这个以使其成为文字\/
  • 什么是|分隔符?这是两个完全相互作用的部分 - 要么是'整数',要么是'numtor'和'dentor'......那部分看起来很混乱......