.NET रेगेक्स में मैं कैप्चरिंग ग्रुप्स नाम का उपयोग कैसे करूँ?


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> 

मैंने कई अन्य "तरीकों" के साथ प्रयोग किया है जो मुझे विभिन्न वेबसाइटों पर मिले हैं लेकिन मैं एक ही परिणाम प्राप्त कर रहा हूं।

मैं नामांकित कैप्चरिंग समूहों तक कैसे पहुँच सकता हूँ जो मेरे रेगेक्स में निर्दिष्ट हैं?


3
Backreference प्रारूप में होना चाहिए ((? <Link>। *) और नहीं ((? <Link>। *?)
SO उपयोगकर्ता

11
FYI करें: यदि आप एक नामित कैप्चर समूह को एक xml फ़ाइल के अंदर संग्रहीत करने का प्रयास कर रहे हैं, तो <>यह टूट जाएगा। आप (?'link'.*)इस मामले में इसके बजाय उपयोग कर सकते हैं । इस सवाल के लिए पूरी तरह से प्रासंगिक नहीं है, लेकिन मैं ".net पर कब्जा समूहों" का एक Google खोज से यहाँ उतरा "तो मुझे यकीन है कि अन्य लोग भी हैं ...
rtpHarry

1
StackOverflow लिंक अच्छे उदाहरण के साथ: stackoverflow.com/a/1381163/463206 इसके अलावा, @rtpHarry, नहीं <>इसे नहीं तोड़ेगा । मैं myRegex.GetGroupNames()XML तत्व नामों के रूप में संग्रह का उपयोग करने में सक्षम था ।
रडारबॉब

जवाबों:


263

मैच ऑब्जेक्ट के समूह संग्रह का उपयोग करें, इसे कैप्चरिंग ग्रुप नाम के साथ अनुक्रमित करें, जैसे

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

10
उपयोग न करें var m, क्योंकि यह एक होगा object
थॉमस वेलर

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 स्ट्रिंग पैटर्न से मेल खाता है या नहीं। यदि यह मेल खाता है, तो बाहर के पैरामियों में क्रमशः लिंक और नाम होता है।

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

यह जवाब रश्मि पंडित के जवाब में सुधार करता है , जो एक तरह से बाकी की तुलना में बेहतर है क्योंकि यह सवाल में विस्तृत सटीक समस्या को पूरी तरह से हल करने के लिए लगता है।

बुरा हिस्सा यह है कि अक्षम है और लगातार इग्नोरकेस विकल्प का उपयोग नहीं करता है।

अक्षम्य भाग इसलिए है क्योंकि रेगेक्स निर्माण और निष्पादित करने के लिए महंगा हो सकता है, और उस उत्तर में इसका निर्माण सिर्फ एक बार किया जा सकता Regex.IsMatchथा (कॉलिंग सिर्फ दृश्य के पीछे रेगेक्स का निर्माण कर रहा था)। और Matchविधि सकता है केवल एक बार कहा जाता है किया गया है और एक चर में संग्रहीत और फिर linkऔर nameबुलाना चाहिएResult कि चर से।

और इग्नोरकेस विकल्प का उपयोग केवल 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;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.