जब एक regexp में समूह होते हैं, तो इसके खिलाफ एक स्ट्रिंग से मेल खाने का एक से अधिक तरीका हो सकता है: समूहों के साथ regexps अस्पष्ट हैं। उदाहरण के लिए, regexp ^.*\([0-9][0-9]*\)$और स्ट्रिंग पर विचार करें a12। दो संभावनाएँ हैं:
- के
aखिलाफ .*और 2खिलाफ मैच [0-9]*; 1द्वारा मिलान किया जाता है [0-9]।
- मैच के
a1खिलाफ .*और खाली स्ट्रिंग के खिलाफ [0-9]*; 2द्वारा मिलान किया जाता है [0-9]।
एसईडी, अन्य सभी रेगेक्सप टूल्स की तरह, सबसे लंबा सबसे लंबा मैच नियम लागू करता है: यह पहली बार एक स्ट्रिंग के खिलाफ पहले वैरिएबल-लंबाई वाले हिस्से से मिलान करने की कोशिश करता है जो कि यथासंभव लंबे समय तक होता है। यदि यह शेष रेगेक्सपी के खिलाफ बाकी स्ट्रिंग से मिलान करने का एक तरीका ढूंढता है, तो ठीक है। अन्यथा, sed पहले चर-लंबाई वाले हिस्से के लिए अगले सबसे लंबे मैच की कोशिश करता है और फिर से कोशिश करता है।
यहां, सबसे लंबे स्ट्रिंग के साथ मैच पहले के a1खिलाफ है .*, इसलिए समूह केवल मैच करता है 2। यदि आप चाहते हैं कि समूह पहले शुरू हो, तो कुछ regexp इंजन आपको .*कम लालची बनाते हैं , लेकिन sed में ऐसी सुविधा नहीं है। तो आपको कुछ अतिरिक्त एंकर के साथ अस्पष्टता को दूर करने की आवश्यकता है । निर्दिष्ट करें कि अग्रणी .*एक अंक के साथ समाप्त नहीं हो सकता है, ताकि समूह का पहला अंक पहला संभव मैच हो।
यदि अंकों का समूह लाइन की शुरुआत में नहीं हो सकता है:
sed -n 's/^.*[^0-9]\([0-9][0-9]*\).*/\1/p'
यदि अंकों का समूह लाइन की शुरुआत में हो सकता है, और आपका sed \?वैकल्पिक भागों के लिए ऑपरेटर का समर्थन करता है :
sed -n 's/^\(.*[^0-9]\)\?\([0-9][0-9]*\).*/\1/p'
यदि अंकों का समूह लाइन की शुरुआत में हो सकता है, तो मानक रेगेक्स निर्माणों से चिपके रहते हैं:
sed -n -e 's/^.*[^0-9]\([0-9][0-9]*\).*/\1/p' -e t -e 's/^\([0-9][0-9]*\).*/\1/p'
वैसे, यह सबसे पुराना सबसे लंबा मैच नियम है जो [0-9]*बाद के बजाय पहले एक के बाद के अंकों से मेल खाता है .*।
ध्यान दें कि यदि किसी रेखा पर अंकों के कई अनुक्रम हैं, तो आपका कार्यक्रम हमेशा अंकों के अंतिम अनुक्रम को निकालेगा, प्रारंभिक के लिए सबसे लंबे समय तक मिलान नियम के कारण .*। यदि आप अंकों के पहले अनुक्रम को निकालना चाहते हैं, तो आपको यह निर्दिष्ट करना होगा कि जो पहले आता है वह गैर-अंकों का अनुक्रम है।
sed -n 's/^[^0-9]*\([0-9][0-9]*\).*$/\1/p'
अधिक आम तौर पर, एक regexp के पहले मैच को निकालने के लिए, आपको उस regexp के निषेध की गणना करने की आवश्यकता है। जबकि यह हमेशा सैद्धांतिक रूप से संभव होता है, नकार का आकार तेजी से बढ़ता है उस regexp के आकार के साथ जो आप नकार रहे हैं, इसलिए यह अक्सर अव्यवहारिक होता है।
अपने अन्य उदाहरण पर विचार करें:
sed -n 's/.*\(CONFIG_[a-zA-Z0-9_]*\).*/\1/p'
यह उदाहरण वास्तव में एक ही मुद्दे को प्रदर्शित करता है, लेकिन आप इसे विशिष्ट इनपुट पर नहीं देखते हैं। यदि आप इसे खिलाते हैं hello CONFIG_FOO_CONFIG_BAR, तो ऊपर का कमांड प्रिंट करता है CONFIG_BAR, नहीं CONFIG_FOO_CONFIG_BAR।
पहले मैच को sed के साथ प्रिंट करने का एक तरीका है, लेकिन यह थोड़ा मुश्किल है:
sed -n -e 's/\(CONFIG_[a-zA-Z0-9_]*\).*/\n\1/' -e T -e 's/^.*\n//' -e p
(मान लिया जाए कि आपकी सेड रिप्लेसमेंट टेक्स्ट \nमें एक न्यूलाइन का मतलब है s।) यह काम करता है क्योंकि सेड रेक्सएक्सपी के सबसे शुरुआती मैच के लिए दिखता है, और हम उस CONFIG_…बिट को प्रीएर्ड करने की कोशिश नहीं करते हैं । चूंकि लाइन के अंदर कोई नई रेखा नहीं है, इसलिए हम इसे अस्थायी मार्कर के रूप में उपयोग कर सकते हैं। Tआदेश देने के लिए करता है, तो पूर्ववर्ती कहते हैं sआदेश मेल नहीं खाती।
जब आप समझ नहीं सकते कि कैसे कुछ सेड में किया जाए, तो जागने के लिए मुड़ें। निम्न कमांड एक regexp का सबसे लंबा सबसे लंबा मैच प्रिंट करता है:
awk 'match($0, /[0-9]+/) {print substr($0, RSTART, RLENGTH)}'
और अगर आपको यह आसान लग रहा है, तो पर्ल का उपयोग करें।
perl -l -ne '/[0-9]+/ && print $&' # first match
perl -l -ne '/^.*([0-9]+)/ && print $1' # last match