簡體   English   中英

如何訪問 .NET Regex 中的命名捕獲組?

[英]How do I access named capturing groups in a .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> 

我已經嘗試過在各種網站上找到的其他幾種“方法”,但我一直得到相同的結果。

如何訪問在我的正則表達式中指定的命名捕獲組?

使用 Match 對象的組集合,使用捕獲組名稱對其進行索引,例如

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

您可以通過將命名的捕獲組字符串傳遞給生成的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);
        }
    }
}

下面的代碼示例即使在中間有空格字符的情況下也會匹配模式。 IE :

<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 字符串是否與模式匹配。 如果匹配,則輸出參數分別包含鏈接和名稱。

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

我已經測試過這個並且它工作正常。

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

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

這個答案改進了Rashmi Pandit 的答案,在某種程度上比其他答案更好,因為它似乎完全解決了問題中詳述的確切問題。

不好的部分是效率低下,並且不會始終如一地使用 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;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM