如何在.NET Regex中访问命名捕获组?

时间:2009-05-25 12:11:01

标签: c# .net regex

我很难找到一个很好的资源来解释如何在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> 

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

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

5 个答案:

答案 0 :(得分:251)

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

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

答案 1 :(得分:104)

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

这是一个小例子:

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);
        }
    }
}

答案 2 :(得分:11)

以下代码示例即使中间有空格字符,也会匹配该模式。 即:

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

以及:

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

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

/// <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;
}

我测试了这个并且它可以正常工作。

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

此答案在Rashmi Pandit's answer上得到了改进,在某种程度上比其他方法要好,因为它似乎可以完全解决问题中详述的确切问题。

不好的地方是效率低下并且不能始终使用IgnoreCase选项。

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

IgnoreCase选项仅在Match部分中使用,而没有在Regex.IsMatch部分中使用。

我也将正则表达式定义移到了该方法之外,以便仅构造一次(如果我们使用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;
    }
}