【问题标题】:How do I access named capturing groups in a .NET Regex?如何访问 .NET Regex 中的命名捕获组?
【发布时间】:2021-08-23 02:37:40
【问题描述】:

我很难找到一个很好的资源来解释如何在 C# 中使用命名捕获组。这是我到目前为止的代码:

string page = Encoding.ASCII.GetString(bytePage);
Regex qariRegex = new Regex("<td><a href=\"(?<link>.*?)\">(?<name>.*?)</a></td>");
MatchCollection mc = qariRegex.Matches(page);
CaptureCollection cc = mc[0].Captures;
MessageBox.Show(cc[0].ToString());

但是这总是只显示整行:

<td><a href="/path/to/file">Name of File</a></td> 

我已经尝试过在各种网站上找到的其他几种“方法”,但我一直得到相同的结果。

如何访问在我的正则表达式中指定的命名捕获组?

【问题讨论】:

  • 反向引用的格式应该是 (?.*) 而不是 (?.*?)
  • 仅供参考:如果您尝试将命名的捕获组存储在 xml 文件中,那么 &lt;&gt; 会破坏它。在这种情况下,您可以改用 (?'link'.*)。与这个问题不完全相关,但我从谷歌搜索“.net named capture groups”来到这里,所以我相信其他人也是如此......
  • StackOverflow 链接有很好的例子:stackoverflow.com/a/1381163/463206 另外,@rtpHarry,不,&lt;&gt; 不会破坏它。我能够使用 myRegex.GetGroupNames() 集合作为 XML 元素名称。

标签: c# .net regex


【解决方案1】:

使用 Match 对象的组集合,使用捕获组名称对其进行索引,例如

foreach (Match m in mc){
    MessageBox.Show(m.Groups["link"].Value);
}

【讨论】:

  • 不要使用var m,因为那会是object
【解决方案2】:

您可以通过将命名的捕获组字符串传递给生成的Match 对象的Groups 属性的索引器来指定它。

这是一个小例子:

using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        String sample = "hello-world-";
        Regex regex = new Regex("-(?<test>[^-]*)-");

        Match match = regex.Match(sample);

        if (match.Success)
        {
            Console.WriteLine(match.Groups["test"].Value);
        }
    }
}

【讨论】:

    【解决方案3】:

    以下代码示例即使在中间有空格字符的情况下也会匹配模式。 即:

    <td><a href='/path/to/file'>Name of File</a></td>
    

    还有:

    <td> <a      href='/path/to/file' >Name of File</a>  </td>
    

    方法返回真或假,取决于输入的 htmlTd 字符串是否与模式匹配。如果匹配,则输出参数分别包含链接和名称。

    /// <summary>
    /// Assigns proper values to link and name, if the htmlId matches the pattern
    /// </summary>
    /// <returns>true if success, false otherwise</returns>
    public static bool TryGetHrefDetails(string htmlTd, out string link, out string name)
    {
        link = null;
        name = null;
    
        string pattern = "<td>\\s*<a\\s*href\\s*=\\s*(?:\"(?<link>[^\"]*)\"|(?<link>\\S+))\\s*>(?<name>.*)\\s*</a>\\s*</td>";
    
        if (Regex.IsMatch(htmlTd, pattern))
        {
            Regex r = new Regex(pattern,  RegexOptions.IgnoreCase | RegexOptions.Compiled);
            link = r.Match(htmlTd).Result("${link}");
            name = r.Match(htmlTd).Result("${name}");
            return true;
        }
        else
            return false;
    }
    

    我已经对此进行了测试,它可以正常工作。

    【讨论】:

    • 感谢您提醒我花括号可以访问组。我更喜欢坚持${1} 以使事情变得更简单。
    • 这完全回答了问题,但有些问题在这里解释太长了,但我在my answer below中解释并纠正了这些问题
    【解决方案4】:

    此外,如果有人有一个用例,在他可以使用的 Regex 对象上执行搜索之前需要组名:

    var regex = new Regex(pattern); // initialized somewhere
    // ...
    var groupNames = regex.GetGroupNames();
    

    【讨论】:

      【解决方案5】:

      这个答案改进了Rashmi Pandit's answer,这在某种程度上比其他答案更好,因为它似乎完全解决了问题中详述的确切问题。

      不好的部分是效率低下并且没有始终如一地使用 IgnoreCase 选项。

      效率低下的部分是因为正则表达式的构建和执行成本很高,而在那个答案中,它可能只构建一次(调用Regex.IsMatch 只是在幕后再次构建正则表达式)。而Match 方法可能只被调用一次并存储在一个变量中,然后linkname 应该从该变量调用Result

      并且 IgnoreCase 选项仅用于Match 部分,但未用于Regex.IsMatch 部分。

      我还将 Regex 定义移到方法之外,以便只构造一次(如果我们使用 RegexOptions.Compiled 选项存储该程序集,我认为这是明智的做法)。

      private static Regex hrefRegex = new Regex("<td>\\s*<a\\s*href\\s*=\\s*(?:\"(?<link>[^\"]*)\"|(?<link>\\S+))\\s*>(?<name>.*)\\s*</a>\\s*</td>",  RegexOptions.IgnoreCase | RegexOptions.Compiled);
      
      public static bool TryGetHrefDetails(string htmlTd, out string link, out string name)
      {
          var matches = hrefRegex.Match(htmlTd);
          if (matches.Success)
          {
              link = matches.Result("${link}");
              name = matches.Result("${name}");
              return true;
          }
          else
          {
              link = null;
              name = null;
              return false;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-03
        • 2022-01-12
        • 2020-01-22
        • 1970-01-01
        • 2014-06-26
        • 1970-01-01
        相关资源
        最近更新 更多