代码之家  ›  专栏  ›  技术社区  ›  Dinah SLaks

.NET正则表达式捕获的顺序不符合预期

  •  5
  • Dinah SLaks  · 技术社区  · 15 年前

    此正则表达式用于配方成分(为了示例而简化):

    (?<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
    [牙齿][ 0 ]=2
    [单位][0]=tbsp
    [单位][ 1 ]=总悬浮颗粒物

    注意,即使 1/2 tsp [0]

    有没有办法让所有部分都有可预测的有用索引,而不必再次通过regex重新运行每个组?

    3 回复  |  直到 15 年前
        1
  •  1
  •   Alan Moore Chris Ballance    15 年前

    有没有办法让所有部分都有可预测的有用索引,而不必再次通过regex重新运行每个组?

    不是捕获。如果你要进行多次匹配,我建议你移除 +

      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 在开始处确保匹配只发生在上一个匹配结束的点(如果这是第一次匹配尝试,则在输入的开始处)。您还可以保存调用之间的匹配结束位置,然后使用two参数 Matches 方法在同一点恢复解析(就好像那是输入的真正开始)。

        2
  •  1
  •   LarsH    15 年前

        3
  •  -1
  •   t0mm13b    15 年前

    看看这个……这里有几个建议可能有助于改进regexp

    (?<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? 而不是 \. 捕捉空格,因为它正在逃逸句号,并期望在某处出现句号。。
    • 像这样避开/使其成为文字 \/
    • 分隔符是用来做什么的?这是两个完全相互的部分,要么是一个整数,要么是一个带dentor的numtor。。。那部分看起来很混乱。。。