ฉันจะเข้าถึงกลุ่มที่มีชื่อใน. NET Regex ได้อย่างไร


255

ฉันมีปัญหาในการค้นหาแหล่งข้อมูลที่ดีซึ่งอธิบายวิธีใช้กลุ่มจับภาพที่ระบุชื่อใน 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> 

ฉันได้ทดลองกับ "วิธีการ" อื่น ๆ อีกหลายวิธีที่ฉันพบในเว็บไซต์ต่างๆ แต่ฉันก็ยังได้ผลลัพธ์เหมือนเดิม

ฉันจะเข้าถึงกลุ่มที่มีชื่อที่ระบุไว้ใน regex ของฉันได้อย่างไร


3
การอ้างอิงกลับควรอยู่ในรูปแบบ (? <link>. *) และไม่ (? <link>. *?)
ผู้ใช้ SO

11
FYI: หากคุณพยายามจัดเก็บกลุ่มการดักจับที่ระบุชื่อไว้ในไฟล์ xml ข้อมูล<>จะถูกทำลาย คุณสามารถใช้(?'link'.*)แทนในกรณีนี้ ไม่เกี่ยวข้องทั้งหมดกับคำถามนี้ แต่ฉันมาที่นี่จากการค้นหาโดย Google ของ ".net ชื่อกลุ่มจับภาพ" ดังนั้นฉันจึงมั่นใจว่าคนอื่น ๆ ก็เช่นกัน ...
rtpHarry

1
ลิงก์ StackOverflow ด้วยตัวอย่างที่ดี: stackoverflow.com/a/1381163/463206 นอกจากนี้ @rtpHarry <>จะไม่มีการแตกหัก ฉันสามารถใช้myRegex.GetGroupNames()คอลเลกชันเป็นชื่อองค์ประกอบ XML
Radarbob

คำตอบ:



111

คุณระบุสตริงกลุ่มการจับภาพที่มีชื่อโดยส่งไปยังตัวสร้างดัชนีของ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);
        }
    }
}

10

ตัวอย่างโค้ดต่อไปนี้จะจับคู่รูปแบบแม้ในกรณีที่อักขระเว้นวรรคอยู่ระหว่าง เช่น:

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

เช่นเดียวกับ:

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

วิธีการคืนค่าจริงหรือเท็จขึ้นอยู่กับว่าสตริงการป้อน htmlTd ตรงกับรูปแบบหรือไม่ ถ้ามันตรงกัน params 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;
}

ฉันทดสอบสิ่งนี้แล้วและทำงานได้อย่างถูกต้อง


1
ขอบคุณที่เตือนฉันว่าเครื่องมือจัดฟันแบบหยิกสามารถเข้าถึงกลุ่มได้ ฉันชอบที่จะยึดติดกับ${1}สิ่งต่าง ๆ ได้ง่ายขึ้น
แมกนัสสมิ ธ

สิ่งนี้ตอบคำถามได้อย่างสมบูรณ์ แต่มีปัญหาบางอย่างที่เกินกว่าจะอธิบายได้ที่นี่ แต่ฉันอธิบายและแก้ไขคำตอบของฉันด้านล่างนี้
Mariano Desanze

1

นอกจากนี้หากมีคนใช้กรณีที่เขาต้องการชื่อกลุ่มก่อนดำเนินการค้นหาบนวัตถุ Regex เขาสามารถใช้:

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

1

คำตอบนี้ปรับปรุงจากคำตอบของ Rashmi Panditซึ่งดีกว่าส่วนที่เหลือเพราะดูเหมือนว่าจะสามารถแก้ไขปัญหาที่มีรายละเอียดในคำถามได้อย่างสมบูรณ์

ส่วนที่ไม่ดีคือไม่มีประสิทธิภาพและไม่ได้ใช้ตัวเลือก IgnoreCase อย่างสม่ำเสมอ

ส่วนที่ไม่มีประสิทธิภาพนั้นเป็นเพราะ regex อาจมีราคาแพงในการสร้างและดำเนินการและในคำตอบนั้นมันอาจถูกสร้างขึ้นเพียงครั้งเดียว (การเรียกRegex.IsMatchเป็นเพียงการสร้าง regex อีกครั้งหลังฉาก) และMatchวิธีการอาจถูกเรียกเพียงครั้งเดียวและเก็บไว้ในตัวแปรแล้วlinkและnameควรเรียก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;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.