गैर-कैप्चरिंग समूह, अर्थात (?:)
, नियमित अभिव्यक्ति में कैसे उपयोग किए जाते हैं और वे किसके लिए अच्छे हैं?
गैर-कैप्चरिंग समूह, अर्थात (?:)
, नियमित अभिव्यक्ति में कैसे उपयोग किए जाते हैं और वे किसके लिए अच्छे हैं?
जवाबों:
मुझे एक उदाहरण के साथ यह समझाने की कोशिश करते हैं।
निम्नलिखित पाठ पर विचार करें:
http://stackoverflow.com/
/programming/tagged/regex
अब, अगर मैं इसके ऊपर रेगेक्स लागू करता हूं ...
(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
... मुझे निम्नलिखित परिणाम मिलेगा:
Match "http://stackoverflow.com/"
Group 1: "http"
Group 2: "stackoverflow.com"
Group 3: "/"
Match "/programming/tagged/regex"
Group 1: "https"
Group 2: "stackoverflow.com"
Group 3: "/questions/tagged/regex"
लेकिन मुझे प्रोटोकॉल की परवाह नहीं है - मैं केवल URL का होस्ट और पथ चाहता हूं। इसलिए, मैं गैर-कैप्चरिंग समूह को शामिल करने के लिए रेगेक्स को बदलता हूं (?:)
।
(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
अब, मेरा परिणाम इस तरह दिखता है:
Match "http://stackoverflow.com/"
Group 1: "stackoverflow.com"
Group 2: "/"
Match "/programming/tagged/regex"
Group 1: "stackoverflow.com"
Group 2: "/questions/tagged/regex"
देख? पहले समूह पर कब्जा नहीं किया गया है। पार्सर पाठ का मिलान करने के लिए इसका उपयोग करता है, लेकिन बाद में इसे अंतिम परिणाम में अनदेखा कर देता है।
जैसा कि अनुरोध किया गया है, मुझे समूहों को भी समझाने की कोशिश करें।
वैसे, समूह कई उद्देश्यों की पूर्ति करते हैं। वे एक बड़े मैच से सटीक जानकारी निकालने में आपकी सहायता कर सकते हैं (जिसका नाम भी लिया जा सकता है), वे आपको पिछले मिलान वाले समूह को रीमैच करने देते हैं, और प्रतिस्थापन के लिए उपयोग किया जा सकता है। चलो कुछ उदाहरणों की कोशिश करेंगे, क्या हम?
कल्पना कीजिए कि आपके पास किसी प्रकार का XML या HTML हो (ध्यान रखें कि regex नौकरी के लिए सबसे अच्छा साधन नहीं हो सकता है , लेकिन यह एक उदाहरण के रूप में अच्छा है)। आप टैग को पार्स करना चाहते हैं, इसलिए आप ऐसा कुछ कर सकते हैं (मैंने इसे समझने के लिए आसान बनाने के लिए स्थान जोड़े हैं):
\<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
\<(.+?)\> [^<]*? \</\1\>
पहले रेगेक्स का एक नामित समूह (TAG) है, जबकि दूसरा एक सामान्य समूह का उपयोग करता है। दोनों regexes एक ही काम करते हैं: वे समापन समूह से मिलान करने के लिए पहले समूह (टैग का नाम) से मूल्य का उपयोग करते हैं। अंतर यह है कि पहले एक मूल्य का मिलान करने के लिए नाम का उपयोग करता है, और दूसरा समूह सूचकांक का उपयोग करता है (जो 1 से शुरू होता है)।
आइए अब कुछ प्रतिस्थापन का प्रयास करें। निम्नलिखित पाठ पर विचार करें:
Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.
अब, चलो इस पर इस गूंगा regex का उपयोग करें:
\b(\S)(\S)(\S)(\S*)\b
यह रेगेक्स कम से कम 3 अक्षरों के साथ शब्दों से मेल खाता है, और पहले तीन अक्षरों को अलग करने के लिए समूहों का उपयोग करता है। परिणाम यह है:
Match "Lorem"
Group 1: "L"
Group 2: "o"
Group 3: "r"
Group 4: "em"
Match "ipsum"
Group 1: "i"
Group 2: "p"
Group 3: "s"
Group 4: "um"
...
Match "consectetuer"
Group 1: "c"
Group 2: "o"
Group 3: "n"
Group 4: "sectetuer"
...
इसलिए, यदि हम प्रतिस्थापन स्ट्रिंग लागू करते हैं:
$1_$3$2_$4
... इसके ऊपर, हम पहले समूह का उपयोग करने का प्रयास कर रहे हैं, एक अंडरस्कोर जोड़ते हैं, तीसरे समूह का उपयोग करते हैं, फिर दूसरे समूह का, दूसरे अंडरस्कोर को जोड़ते हैं, और फिर चौथे समूह को जोड़ते हैं। परिणामस्वरूप स्ट्रिंग नीचे की तरह होगा।
L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.
आप नामांकित समूहों का उपयोग प्रतिस्थापन के लिए भी कर सकते हैं ${name}
।
रेगेक्स के साथ खेलने के लिए, मैं http://regex101.com/ की सिफारिश करता हूं , जो रेगेक्स कैसे काम करता है, इस पर अच्छी मात्रा में विवरण प्रदान करता है; यह चुनने के लिए कुछ रेगेक्स इंजन भी प्रदान करता है।
अभिव्यक्ति को व्यवस्थित और पार्स करने के लिए आप कैप्चरिंग समूहों का उपयोग कर सकते हैं। एक गैर-कैप्चरिंग समूह का पहला लाभ होता है, लेकिन दूसरे का ओवरहेड नहीं होता है। आप अभी भी कह सकते हैं कि गैर-कैप्चरिंग समूह वैकल्पिक है, उदाहरण के लिए।
मान लें कि आप संख्यात्मक पाठ से मेल खाना चाहते हैं, लेकिन कुछ संख्याएँ 1, 2, 3, 4, 4 के रूप में लिखी जा सकती हैं ... यदि आप संख्यात्मक भाग को कैप्चर करना चाहते हैं, लेकिन वैकल्पिक (वैकल्पिक) प्रत्यय नहीं है तो आप गैर-कैप्चरिंग समूह का उपयोग कर सकते हैं ।
([0-9]+)(?:st|nd|rd|th)?
यह 1, 2, 3 ... या 1, 2, 3, ... के रूप में संख्याओं से मेल खाएगा, लेकिन यह केवल संख्यात्मक भाग पर कब्जा करेगा।
?:
का उपयोग तब किया जाता है जब आप एक अभिव्यक्ति को समूह बनाना चाहते हैं, लेकिन आप इसे स्ट्रिंग के मिलान / कैप्चर किए गए हिस्से के रूप में सहेजना नहीं चाहते हैं।
एक उदाहरण एक आईपी पते से मेल खाने के लिए कुछ होगा:
/(?:\d{1,3}\.){3}\d{1,3}/
ध्यान दें कि मुझे पहले 3 ओकटेट्स को बचाने के बारे में परवाह नहीं है, लेकिन (?:...)
समूहीकरण मुझे एक मैच पर कब्जा करने और भंडारण करने के ओवरहेड के बिना रेगेक्स को छोटा करने की अनुमति देता है।
यह समूह को गैर-कैप्चरिंग बनाता है, जिसका अर्थ है कि उस समूह द्वारा मिलान किया जाने वाला सबस्ट्रिंग कैप्चर की सूची में शामिल नहीं होगा। माणिक में एक उदाहरण के अंतर को स्पष्ट करने के लिए:
"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
(?:)
एक कैप्चर का उत्पादन नहीं होता है, न कि एक उपयोगी उदाहरण का प्रदर्शन करने के लिए (?:)
। (?:)
तब उपयोगी होता है जब आप एक उप-अभिव्यक्ति को समूह बनाना चाहते हैं (जब आप एक गैर-परमाणु उप-अभिव्यक्ति के लिए क्वांटिफायर लागू करना चाहते हैं या यदि आप एक के दायरे को प्रतिबंधित करना चाहते हैं |
), लेकिन आप कुछ भी कैप्चर नहीं करना चाहते हैं।
व्यावसायिक प्रेरणा:
गैर-कैप्चरिंग समूहों के अस्तित्व को कोष्ठक के उपयोग के साथ समझाया जा सकता है।
अभिव्यक्तियों पर विचार करें (a|b)c
और a|bc
, सहमति से अधिक की प्राथमिकता के कारण |
, ये अभिव्यक्तियाँ दो भिन्न भाषाओं ( {ac, bc}
और) का प्रतिनिधित्व करती हैं{a, bc}
क्रमशः) का ।
हालाँकि, कोष्ठक का उपयोग मिलान समूह के रूप में भी किया जाता है (जैसा कि अन्य उत्तरों द्वारा समझाया गया है ...)।
जब आप कोष्ठक करना चाहते हैं, लेकिन उप-अभिव्यक्ति को कैप्चर नहीं करते हैं जिसका उपयोग आप गैर-कैप्चरिंग ग्रूप करते हैं। उदाहरण में,(?:a|b)c
मुझे एक उदाहरण के साथ यह कोशिश करने दें:
रेगेक्स कोड: (?:animal)(?:=)(\w+)(,)\1\2
खोज स्ट्रिंग:
पंक्ति 1 - animal=cat,dog,cat,tiger,dog
लाइन 2 - animal=cat,cat,dog,dog,tiger
पंक्ति 3 - animal=dog,dog,cat,cat,tiger
(?:animal)
-> गैर-कब्जा समूह १
(?:=)
-> गैर-कब्जा समूह 2
(\w+)
-> कब्जा किया हुआ समूह 1
(,)
-> कब्जा समूह 2
\1
-> पकड़े गए समूह 1 का परिणाम। लाइन 1 में बिल्ली है, लाइन 2 में बिल्ली है, लाइन 3 में कुत्ता है।
\2
-> पकड़े गए समूह 2 का परिणाम अर्थात अल्पविराम (,)
तो इस कोड में देकर \1
और\2
हम कोड में क्रमशः बाद में पकड़े गए समूह 1 और 2 के परिणाम को याद करते हैं या दोहराते हैं।
कोड के आदेश के अनुसार (?:animal)
समूह 1 और होना चाहिए(?:=)
होना चाहिए समूह 2 होना चाहिए और जारी रहना चाहिए।
लेकिन ?:
हम मैच-समूह को गैर-कैप्चर करते हैं (जो कि मिलान किए गए समूह में नहीं गिना जाता है, इसलिए समूहन संख्या पहले कैप्चर किए गए समूह से शुरू होती है और गैर-कैप्चर नहीं होती है), ताकि मैच-समूह के परिणाम की पुनरावृत्ति हो(?:animal)
कोड में बाद में नहीं बुलाया जा सकता है।
आशा है कि यह गैर कैप्चरिंग समूह के उपयोग की व्याख्या करता है।
जिन समूहों को आप कैप्चर करते हैं, वे बाद में रेगेक्स में मैच के लिए उपयोग कर सकते हैं या आप रेगेक्स के प्रतिस्थापन भाग में उनका उपयोग कर सकते हैं। एक गैर-कैप्चरिंग समूह बनाना केवल उस समूह को इन कारणों में से किसी एक के लिए उपयोग करने से छूट देता है।
यदि आप कई अलग-अलग चीजों को पकड़ने की कोशिश कर रहे हैं तो गैर-कैप्चरिंग समूह बहुत अच्छे हैं और कुछ समूह ऐसे हैं जिन्हें आप कैप्चर नहीं करना चाहते हैं।
बहुत अधिक कारण वे मौजूद हैं। जब आप समूहों के बारे में सीख रहे हैं , तो परमाणु समूहों के बारे में जानें , वे बहुत कुछ करते हैं! लुकअराउंड समूह भी हैं, लेकिन वे थोड़े अधिक जटिल हैं और उनका इतना उपयोग नहीं किया जाता है।
रेगेक्स (पश्चगामी) में बाद में उपयोग करने का उदाहरण:
<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1>
[एक xml टैग ढूँढता है (बिना ns समर्थन के)]
([A-Z][A-Z0-9]*)
एक कैप्चरिंग ग्रुप है (इस मामले में यह टैग्नैम है)
बाद में रेगेक्स में \1
जिसका अर्थ है कि यह केवल उसी पाठ से मेल खाएगा जो पहले समूह ( ([A-Z][A-Z0-9]*)
समूह) में था (इस मामले में यह अंतिम टैग से मेल खा रहा है)।
वैसे मैं एक जावास्क्रिप्ट डेवलपर हूं और जावास्क्रिप्ट से संबंधित इसके महत्व को समझाने की कोशिश करूंगा।
एक परिदृश्य पर विचार करें जहां आप मैच करना चाहते हैं cat is animal
जब आप मैच बिल्ली और जानवर को पसंद करेंगे और दोनों के is
बीच में होना चाहिए ।
// this will ignore "is" as that's is what we want
"cat is animal".match(/(cat)(?: is )(animal)/) ;
result ["cat is animal", "cat", "animal"]
// using lookahead pattern it will match only "cat" we can
// use lookahead but the problem is we can not give anything
// at the back of lookahead pattern
"cat is animal".match(/cat(?= is animal)/) ;
result ["cat"]
//so I gave another grouping parenthesis for animal
// in lookahead pattern to match animal as well
"cat is animal".match(/(cat)(?= is (animal))/) ;
result ["cat", "cat", "animal"]
// we got extra cat in above example so removing another grouping
"cat is animal".match(/cat(?= is (animal))/) ;
result ["cat", "animal"]
जटिल नियमित अभिव्यक्तियों में आपके पास ऐसी स्थिति उत्पन्न हो सकती है जहां आप बड़ी संख्या में समूहों का उपयोग करना चाहते हैं, जिनमें से कुछ पुनरावृत्ति मिलान के लिए हैं और जिनमें से कुछ वापस संदर्भ प्रदान करने के लिए हैं। डिफ़ॉल्ट रूप से प्रत्येक समूह से मेल खाने वाले पाठ को बैकरेक्शन सरणी में लोड किया जाता है। जहां हमारे पास बहुत सारे समूह हैं और केवल उनमें से कुछ को बैकरेक्शन एरे से संदर्भित करने में सक्षम होने की आवश्यकता है, हम इस डिफ़ॉल्ट व्यवहार को ओवरराइड कर सकते हैं नियमित अभिव्यक्ति बताने के लिए कि कुछ समूह केवल पुनरावृत्ति से निपटने के लिए हैं और उन्हें कैप्चर करने और संग्रहीत करने की आवश्यकता नहीं है बैकरेन्स सरणी में।
मैं यह कहने के लिए शीर्ष उत्तरों पर टिप्पणी नहीं कर सकता: मैं एक स्पष्ट बिंदु जोड़ना चाहूंगा जो केवल शीर्ष उत्तरों में निहित है:
गैर कैप्चरिंग समूह (?...)
करता है को दूर नहीं मूल पूर्ण मैच से किसी भी अक्षर, यह केवल प्रोग्रामर के लिए नेत्रहीन regex reorganises।
परिभाषित एक्सट्रॉनिक वर्णों के बिना रेगेक्स के एक विशिष्ट हिस्से तक पहुंचने के लिए आपको हमेशा उपयोग करने की आवश्यकता होगी .group(<index>)
tl; ड्र -नॉन-कैप्चरिंग ग्रुप्स, जैसा कि नाम से पता चलता है कि रेगेक्स के कुछ भाग हैं जिन्हें आप मैच में शामिल नहीं करना चाहते हैं और ?:
एक ग्रुप को नॉन-कैप्चरिंग के रूप में परिभाषित करने का एक तरीका है।
मान लीजिए कि आपके पास एक ईमेल पता है example@example.com
। निम्नलिखित regex दो समूह बनाएगा , आईडी भाग और @ example.com भाग। (\p{Alpha}*[a-z])(@example.com)
। सादगी के लिए, हम @
चरित्र सहित संपूर्ण डोमेन नाम निकाल रहे हैं ।
अब हम कहते हैं, आपको केवल पते के आईडी भाग की आवश्यकता है। आप जो करना चाहते हैं, वह मैच परिणाम के पहले समूह को हथियाने के लिए है, ()
जो कि रेक्स में घिरा हुआ है और ऐसा करने का तरीका गैर-कैप्चरिंग ग्रुप सिंटैक्स का उपयोग करना है, अर्थात ?:
। तो रेगेक्स (\p{Alpha}*[a-z])(?:@example.com)
ईमेल के आईडी भाग को वापस कर देगा।
एक दिलचस्प बात जो मुझे पता चली है वह यह है कि आपके पास गैर-कैप्चरिंग समूह के अंदर एक कैप्चरिंग ग्रुप हो सकता है। वेब यूआरएल मिलान के लिए regex के नीचे एक नज़र डालें:
var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
इनपुट url स्ट्रिंग:
var url = "http://www.ora.com:80/goodparts?q#fragment";
मेरे रेगेक्स में पहला समूह (?:([A-Za-z]+):)
एक गैर-कैप्चरिंग समूह है, जो प्रोटोकॉल स्कीम और कोलन :
कैरेक्टर से मेल खाता है, http:
लेकिन जब मैं कोड से नीचे चल रहा था, तो मैं देख रहा था कि लौटे हुए सरणी का पहला इंडेक्स स्ट्रिंग से युक्त था http
जब मैं सोच रहा था कि http
और कोलन :
दोनों को रिपोर्ट नहीं किया जाएगा क्योंकि वे एक गैर-कब्जा समूह के अंदर हैं।
console.debug(parse_url_regex.exec(url));
मैंने सोचा कि अगर पहला समूह (?:([A-Za-z]+):)
एक गैर-कैप्चरिंग समूह है तो यह http
आउटपुट ऐरे में स्ट्रिंग क्यों लौटा रहा है ।
इसलिए यदि आप ध्यान दें कि ([A-Za-z]+)
गैर-कैप्चरिंग समूह के अंदर एक नेस्टेड समूह है। वह नेस्टेड समूह एक गैर-कैप्चरिंग समूह के अंदर अपने आप में ([A-Za-z]+)
एक कैप्चरिंग ग्रुप ( ?:
शुरुआत में नहीं) है (?:([A-Za-z]+):)
। इसीलिए टेक्स्ट http
अभी भी कैप्चर हो जाता है लेकिन कोलन :
कैरेक्टर जो नॉन-कैप्चरिंग ग्रुप के अंदर होता है लेकिन कैप्चरिंग ग्रुप के बाहर आउटपुट एरे में रिपोर्ट नहीं किया जाता है।
अपना Google Chrome devTools खोलें और फिर कंसोल टैब: और इसे टाइप करें:
"Peace".match(/(\w)(\w)(\w)/)
इसे चलाएं और आप देखेंगे:
["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]
JavaScript
रेगुलर एक्सप्रेशन इंजन पर कब्जा तीन समूहों, अनुक्रमित 1,2,3 के साथ आइटम नहीं है। अब परिणाम देखने के लिए गैर-कैप्चरिंग मार्क का उपयोग करें।
"Peace".match(/(?:\w)(\w)(\w)/)
परिणाम है:
["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]
यह स्पष्ट है कि गैर कैप्चरिंग ग्रुप क्या है।
मुझे लगता है कि मैं आपको इसका जवाब दूंगा। मैच के सफल होने के बिना कैप्चर चर का उपयोग न करें।
कैप्चर चर, $1
आदि, जब तक कि मैच सफल नहीं हुआ, मान्य नहीं हैं और वे साफ़ नहीं हुए हैं।
#!/usr/bin/perl
use warnings;
use strict;
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
{
print "Fred wants a $1";
}
else
{
print "Fred dont wants a $1 $2";
}
उपरोक्त उदाहरण में $1
, ब्रोंटो को पकड़ने से बचने के लिए ,(?:)
प्रयोग किया जाता है।
यदि पैटर्न का मिलान किया जाता है, तो $1
अगले समूहित पैटर्न के रूप में कैप्चर किया जाता है।
तो, उत्पादन निम्नानुसार होगा:
Fred wants a burger
यदि आप मैचों को सहेजना नहीं चाहते हैं तो यह उपयोगी है।
इसकी अत्यंत सरल, हम सरल तिथि उदाहरण के साथ समझ सकते हैं, मान लें कि तिथि 1 जनवरी 2019 या 2 मई 2019 या किसी अन्य तिथि के रूप में उल्लिखित है और हम इसे केवल dd / mm / yyyy प्रारूप में बदलना चाहते हैं, तो हमें महीने की आवश्यकता नहीं होगी नाम जो उस मामले के लिए जनवरी या फरवरी है, इसलिए संख्यात्मक भाग पर कब्जा करने के लिए, लेकिन (वैकल्पिक) प्रत्यय नहीं आप गैर-कैप्चरिंग समूह का उपयोग कर सकते हैं।
इसलिए नियमित अभिव्यक्ति होगी,
([0-9]+)(?:January|February)?
यह इतना सरल है।