.NET नियमित अभिव्यक्तियों में "समूहों" और "कैप्चर" के बीच क्या अंतर है?


161

मैं थोड़ा सा फजी हूँ कि ".NET" और "कैप्चर" के बीच क्या अंतर है जब यह .NET की नियमित अभिव्यक्ति भाषा की बात आती है। निम्नलिखित सी # कोड पर विचार करें:

MatchCollection matches = Regex.Matches("{Q}", @"^\{([A-Z])\}$");

मुझे उम्मीद है कि 'Q' अक्षर के लिए एक ही कैप्चर किया जा सकता है, लेकिन अगर मैं रिटर्न के गुणों को प्रिंट करता MatchCollectionहूं, तो मैं देखता हूं:

matches.Count: 1
matches[0].Value: {Q}
        matches[0].Captures.Count: 1
                matches[0].Captures[0].Value: {Q}
        matches[0].Groups.Count: 2
                matches[0].Groups[0].Value: {Q}
                matches[0].Groups[0].Captures.Count: 1
                        matches[0].Groups[0].Captures[0].Value: {Q}
                matches[0].Groups[1].Value: Q
                matches[0].Groups[1].Captures.Count: 1
                        matches[0].Groups[1].Captures[0].Value: Q

यहाँ वास्तव में क्या हो रहा है? मैं समझता हूं कि पूरे मैच के लिए कब्जा भी है, लेकिन समूह कैसे आते हैं? और matches[0].Captures'क्यू' अक्षर के लिए कब्जा क्यों शामिल नहीं है ?

जवाबों:


126

आप पहले ऐसे व्यक्ति नहीं होंगे जो इसके बारे में फजी है। यहाँ क्या प्रसिद्ध जेफरी फ्राइडल इसके बारे में कहना है (पृष्ठ 437+):

आपके विचार के आधार पर, यह या तो मैच के परिणामों में एक दिलचस्प नया आयाम जोड़ता है, या भ्रम और ब्लोट जोड़ता है।

और आगे:

समूह ऑब्जेक्ट और कैप्चर ऑब्जेक्ट के बीच मुख्य अंतर यह है कि प्रत्येक समूह ऑब्जेक्ट में मैच के दौरान समूह द्वारा सभी मध्यस्थ मैचों का प्रतिनिधित्व करने वाले कैप्चर का एक संग्रह होता है , साथ ही समूह द्वारा अंतिम पाठ का मिलान किया जाता है।

और कुछ पन्नों के बाद, यह उसका निष्कर्ष है:

.NET डॉक्यूमेंट को पाकर और वास्तव में इन ऑब्जेक्ट्स को जोड़ने के बाद, मुझे उनके बारे में मिश्रित भावनाएं मिली हैं। एक तरफ, यह एक दिलचस्प नवाचार है [..] दूसरी ओर, यह कार्यक्षमता के बोझ को जोड़ने के लिए लगता है [..] एक कार्यक्षमता का जो अधिकांश मामलों में उपयोग नहीं किया जाएगा

दूसरे शब्दों में: वे बहुत समान हैं, लेकिन कभी-कभी और जैसा कि होता है, आप उनके लिए एक उपयोग खोजेंगे। इससे पहले कि आप एक और ग्रे दाढ़ी बढ़ाएं, आप भी कैप्चर के शौकीन हो सकते हैं ...


चूंकि न तो ऊपर, और न ही अन्य पोस्ट में जो कहा गया है वह वास्तव में आपके प्रश्न का उत्तर देता है, निम्नलिखित पर विचार करें। एक प्रकार के इतिहास ट्रैकर के रूप में कैप्चर के बारे में सोचें। जब रेगेक्स अपना मैच बनाता है, तो यह स्ट्रिंग से बाएं से दाएं (एक पल के लिए पीछे हटने वाला) को देखता है और जब यह एक मेल खाने वाले कोष्ठक का सामना करता है, तो यह स्टोर करेगा कि $x(x किसी भी अंक का हो), आइए बताते हैं $1

सामान्य रेगेक्स इंजन, जब कैप्चरिंग कोष्ठकों को दोहराया जाना है, वर्तमान को फेंक $1देगा और इसे नए मूल्य के साथ बदल देगा। .NET नहीं, जो इस इतिहास को रखेगा और इसे इसमें रखेगा Captures[0]

यदि हम निम्न प्रकार से देखने के लिए आपके रेगेक्स को बदलते हैं:

MatchCollection matches = Regex.Matches("{Q}{R}{S}", @"(\{[A-Z]\})+");

आप देखेंगे कि पहले Groupमें एक Captures(पहला समूह हमेशा पूरा मैच होगा, अर्थात, बराबर $0) और दूसरा समूह धारण करेगा {S}, अर्थात केवल अंतिम मिलान समूह। हालांकि, और यहाँ, पकड़ यदि आप अन्य दो कैच खोजना चाहते हैं, वे कर रहे हैं Captures, जिसके लिए सभी मध्यस्थ कैप्चर शामिल {Q} {R}और {S}

यदि आपने कभी सोचा है कि आप कई-कैप्चर से कैसे प्राप्त कर सकते हैं, जो केवल व्यक्तिगत कैप्चर को अंतिम मैच दिखाता है जो स्ट्रिंग में स्पष्ट रूप से वहां हैं, तो आपको उपयोग करना होगा Captures

आपके अंतिम प्रश्न पर एक अंतिम शब्द: कुल मैच में हमेशा एक ही कुल कैप्चर होता है, जो व्यक्तिगत समूहों के साथ नहीं मिलाता है। कब्जा केवल समूहों के अंदर दिलचस्प है


1
a functionality that won't be used in the majority of casesमुझे लगता है कि वह नाव से चूक गया। अल्पावधि में (?:.*?(collection info)){4,20}दक्षता और अधिक बढ़ जाती है कि कुछ सौ प्रतिशत।

1
@sln, निश्चित नहीं है कि आप किसका उल्लेख कर रहे हैं और कौन 'वह' (फ्राइडल?) है। जो उदाहरण आप देते हैं, वह इस चर्चा के लिए असंबंधित है, या प्रयुक्त अभिव्यक्तियों के लिए। इसके अलावा, गैर लालची क्वांटिफायर केवल लालची क्वांटिफायर की तुलना में बहुत अधिक कुशल होते हैं, और इनपुट सेट और सावधान पूर्ण परीक्षण के ज्ञान की आवश्यकता होती है।
हाबिल

@ अविश्वास - मैं इस प्रश्न के डुप्लिकेट के रूप में यहाँ से उतरा। मैंने फ्राइडल को उद्धृत किया। यह पद पुराना है और इसे आधुनिक बनाए रखने के लिए तरोताजा रहने की जरूरत है। केवल डॉट नेट के साथ ही ऐसा किया जा सकता है, यह अन्य लोगों से अलग है। ब्रेक डाउन: एक मात्रा रहित गैर-कैप्चर समग्र समूह उदाहरण (?:..)+। आलसी कुछ भी .*?एक उप उप अभिव्यक्ति (समूह) को मैच । जारी रखना। एक एकल मैच के भीतर, एक समूह संग्रह में सिर्फ एक सरणी की जरूरत होती है। अगले खोजने की कोई आवश्यकता नहीं है, इसे 10 से 20 या अधिक बार तेजी से बनाने का कोई पुन: प्रवेश नहीं है।

1
@sln, यह प्रश्न कुछ और के बारे में है और यह विशेष रूप से एक .net सुविधा के बारे में है जो अन्य रेगेक्स इंजन (समूह बनाम कैप्चर, शीर्षक देखें) में नहीं मिलता है। मुझे यहाँ कुछ भी पुराना नहीं दिखाई दे रहा है, .net अभी भी वही काम कर रहा है, वास्तव में यह हिस्सा लंबे समय से .net में नहीं बदला है। प्रदर्शन सवाल का हिस्सा नहीं है। हां, गैर कैप्चरिंग ग्रुपिंग तेज है, लेकिन फिर, यहां विषय विपरीत है। क्यों आलसी की तुलना में लालची तेज है, कई ग्रंथों में ऑनलाइन और फ्राइडल की पुस्तक द्वारा समझाया गया है, लेकिन यहां ओ.टी. शायद दूसरा सवाल (जो?) एक सच्चा डुप्लिकेट नहीं था?
हाबिल

2
@ विश्वास - मुझे पता है मैं इसे कहता रहता हूं, लेकिन आप इसे नहीं सुनते हैं। मैं फ्रिडल के इस कथन का umbrage लेता हूं a functionality that won't be used in the majority of cases। वास्तव में यह रेगेक्स लैंड में कार्यक्षमता के बाद सबसे अधिक मांग है। आलसी / लालची? मेरी टिप्पणियों का क्या करना है? यह कैप्चर बफ़र्स की एक चर राशि होने में सक्षम बनाता है। यह एक ही मैच में पूरे स्ट्रिंग को स्वीप कर सकता है। अगर .*?(dog)पहले मिल जाता है dogतो एक ही मैच में पूरे स्ट्रिंग में सभी(?:.*?(dog))+ मिल जाएगा । प्रदर्शन में वृद्धि ध्यान देने योग्य है। dog

20

एक समूह वह है जो हमने नियमित अभिव्यक्तियों में समूहों के साथ जोड़ा है

"(a[zx](b?))"

Applied to "axb" returns an array of 3 groups:

group 0: axb, the entire match.
group 1: axb, the first group matched.
group 2: b, the second group matched.

सिवाय इसके कि ये केवल 'कैद किए गए' समूह हैं। गैर कैप्चरिंग ग्रुप्स ('?:' 'सिंटैक्स का उपयोग यहां नहीं किया गया है।

"(a[zx](?:b?))"

Applied to "axb" returns an array of 2 groups:

group 0: axb, the entire match.
group 1: axb, the first group matched.

एक कैप्चर वह भी है जिसे हमने 'कैप्चर ग्रुप्स' के साथ जोड़ा है। लेकिन जब समूह को कई बार एक क्वांटिफायर के साथ लागू किया जाता है, तो केवल अंतिम मैच को समूह के मैच के रूप में रखा जाता है। कैप्चर सरणी इन सभी मैचों को संग्रहीत करती है।

"(a[zx]\s+)+"

Applied to "ax az ax" returns an array of 2 captures of the second group.

group 1, capture 0 "ax "
group 1, capture 1 "az "

आपके अंतिम प्रश्न के रूप में - मैंने इस पर गौर करने से पहले सोचा होगा कि कैप्चर समूह के आदेशों की एक सरणी होगी जो वे संबंधित हैं। बल्कि यह समूहों के लिए एक उपनाम है [०]। बहुत बेकार ।।


स्पष्ट व्याख्या (y)
घसन

19

इसे एक सरल उदाहरण (और चित्रों) के साथ समझाया जा सकता है।

3:10pmनियमित अभिव्यक्ति के साथ मिलान ((\d)+):((\d)+)(am|pm), और मोनो इंटरैक्टिव का उपयोग कर csharp:

csharp> Regex.Match("3:10pm", @"((\d)+):((\d)+)(am|pm)").
      > Groups.Cast<Group>().
      > Zip(Enumerable.Range(0, int.MaxValue), (g, n) => "[" + n + "] " + g);
{ "[0] 3:10pm", "[1] 3", "[2] 3", "[3] 10", "[4] 0", "[5] pm" }

तो 1 कहाँ है? यहां छवि विवरण दर्ज करें

चूंकि कई समूह हैं जो चौथे समूह पर मेल खाते हैं, हम केवल "अंतिम मैच" प्राप्त करते हैं यदि हम समूह का संदर्भ देते हैं (एक निहित के साथ ToString(), वह है)। मध्यवर्ती मैचों को उजागर करने के लिए, हमें Capturesसमूह में गहराई से जाने और संपत्ति का संदर्भ देने की आवश्यकता है :

csharp> Regex.Match("3:10pm", @"((\d)+):((\d)+)(am|pm)").
      > Groups.Cast<Group>().
      > Skip(4).First().Captures.Cast<Capture>().
      > Zip(Enumerable.Range(0, int.MaxValue), (c, n) => "["+n+"] " + c);
{ "[0] 1", "[1] 0" }

यहां छवि विवरण दर्ज करें

इस लेख के सौजन्य से ।


3
अच्छा लेख। एक तस्वीर एक हजार शब्दों के बराबर होती है।
अलेक्सवेई

तुम एक सितारे हो।
मिकेमे

14

MSDN प्रलेखन से :

कैप्चर प्रॉपर्टी की वास्तविक उपयोगिता तब होती है जब एक क्वांटिफायर को एक कैप्चरिंग ग्रुप पर लागू किया जाता है ताकि समूह एक नियमित अभिव्यक्ति में कई सबस्टीट्यूशंस को पकड़ ले। इस स्थिति में, समूह ऑब्जेक्ट में अंतिम कैप्चर किए गए विकल्प के बारे में जानकारी होती है, जबकि कैप्चर प्रॉपर्टी में समूह द्वारा कैप्चर किए गए सभी सबस्ट्रिंग के बारे में जानकारी होती है। निम्नलिखित उदाहरण में, नियमित अभिव्यक्ति \ b (\ w + \ s *) +। एक पूरे वाक्य से मेल खाता है जो एक अवधि में समाप्त होता है। समूह (\ w + \ _ *) + संग्रह में अलग-अलग शब्दों को कैप्चर करता है। क्योंकि समूह संग्रह में केवल अंतिम कैप्चर किए गए विकल्प के बारे में जानकारी है, यह वाक्य में अंतिम शब्द "वाक्य" को कैप्चर करता है। हालाँकि, समूह द्वारा कैप्चर किया गया प्रत्येक शब्द कैप्चर प्रॉपर्टी द्वारा लौटाए गए संग्रह से उपलब्ध है।


4

कल्पना कीजिए कि आपके पास निम्न पाठ इनपुट है dogcatcatcat और एक पैटर्न हैdog(cat(catcat))

इस मामले में, आपके पास 3 समूह हैं, पहला समूह ( प्रमुख समूह) ) मैच से मेल खाता है।

मैच == dogcatcatcat और Group0 ==dogcatcatcat

समूह 1 == catcatcat

समूह 2 == catcat

तो यह सब क्या है?

आइए Regexकक्षा का उपयोग करके C # (.NET) में लिखे गए एक छोटे से उदाहरण पर विचार करें ।

int matchIndex = 0;
int groupIndex = 0;
int captureIndex = 0;

foreach (Match match in Regex.Matches(
        "dogcatabcdefghidogcatkjlmnopqr", // input
        @"(dog(cat(...)(...)(...)))") // pattern
)
{
    Console.Out.WriteLine($"match{matchIndex++} = {match}");

    foreach (Group @group in match.Groups)
    {
        Console.Out.WriteLine($"\tgroup{groupIndex++} = {@group}");

        foreach (Capture capture in @group.Captures)
        {
            Console.Out.WriteLine($"\t\tcapture{captureIndex++} = {capture}");
        }

        captureIndex = 0;
    }

    groupIndex = 0;
    Console.Out.WriteLine();
        }

आउटपुट :

match0 = dogcatabcdefghi
    group0 = dogcatabcdefghi
        capture0 = dogcatabcdefghi
    group1 = dogcatabcdefghi
        capture0 = dogcatabcdefghi
    group2 = catabcdefghi
        capture0 = catabcdefghi
    group3 = abc
        capture0 = abc
    group4 = def
        capture0 = def
    group5 = ghi
        capture0 = ghi

match1 = dogcatkjlmnopqr
    group0 = dogcatkjlmnopqr
        capture0 = dogcatkjlmnopqr
    group1 = dogcatkjlmnopqr
        capture0 = dogcatkjlmnopqr
    group2 = catkjlmnopqr
        capture0 = catkjlmnopqr
    group3 = kjl
        capture0 = kjl
    group4 = mno
        capture0 = mno
    group5 = pqr
        capture0 = pqr

चलो पहले मैच का विश्लेषण करें (match0

आप देख सकते हैं वहाँ तीन हैं नाबालिग समूहों : group3, group4औरgroup5

    group3 = kjl
        capture0 = kjl
    group4 = mno
        capture0 = mno
    group5 = pqr
        capture0 = pqr

उन समूहों (3-5) को मुख्य पैटर्न के ' सबपाटन ' (...)(...)(...)के कारण बनाया गया था (dog(cat(...)(...)(...)))

मूल्य के group3अनुरूप यह कब्जा है ( capture0)। (के मामले में group4और के रूप में group5)। ऐसा इसलिए है क्योंकि समूह दोहराव जैसे नहीं हैं (...){3}


ठीक है, आइए एक और उदाहरण पर विचार करें जहां एक समूह दोहराव है

हम मिलान किया जा से (कोड ऊपर दिखाए गए के लिए) रेगुलर एक्सप्रेशन पैटर्न को संशोधित करते हैं (dog(cat(...)(...)(...)))करने के लिए (dog(cat(...){3})), आप ध्यान देंगे निम्नलिखित है कि वहाँ समूह पुनरावृत्ति : (...){3}

अब आउटपुट बदल गया है:

match0 = dogcatabcdefghi
    group0 = dogcatabcdefghi
        capture0 = dogcatabcdefghi
    group1 = dogcatabcdefghi
        capture0 = dogcatabcdefghi
    group2 = catabcdefghi
        capture0 = catabcdefghi
    group3 = ghi
        capture0 = abc
        capture1 = def
        capture2 = ghi

match1 = dogcatkjlmnopqr
    group0 = dogcatkjlmnopqr
        capture0 = dogcatkjlmnopqr
    group1 = dogcatkjlmnopqr
        capture0 = dogcatkjlmnopqr
    group2 = catkjlmnopqr
        capture0 = catkjlmnopqr
    group3 = pqr
        capture0 = kjl
        capture1 = mno
        capture2 = pqr

फिर से, चलो पहले मैच का विश्लेषण करें ( match0)।

अधिक छोटे समूह नहीं हैं group4 और पुनरावृत्ति केgroup5 कारण ( {n} जिसमें n> = 2 ) उन्हें एक ही समूह में मिला दिया गया है(...){3} group3

इस मामले में, group3मान इसके अनुरूप है capture2( अंतिम कैप्चर , दूसरे शब्दों में)।

अतः यदि आप 3 भीतरी कैप्चर की जरूरत है ( capture0, capture1, capture2) को समूह के माध्यम से चक्र करना होगाCaptures संग्रह।

Сonclusion है: अपने पैटर्न के समूहों को डिज़ाइन करने के तरीके पर ध्यान दें। आपको यह सोचना चाहिए कि समूह के विनिर्देशन के कारण क्या व्यवहार होता है, जैसे (...)(...), (...){2}या (.{3}){2}आदि।


उम्मीद है कि यह कैप्चर , समूह और मैचों के बीच के अंतर पर कुछ प्रकाश डालने में मदद करेगा ।

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