समाधान:
echo 'foo_abc_bar' | sed -r 's/(foo)_((abc)_)?(bar)/\1=\3=\4/g'
क्यों अपने पिछले प्रयास काम नहीं किया:
.*
, लालची है तो regex (foo).*(abc)?.*(bar)
मिलान करने के प्रयास के लिए 'foo_abc_bar'
(foo)
'foo'
से मेल खाएगा, और फिर .*
प्रारंभ में शेष स्ट्रिंग ('_abc_bar'
) से मेल खाता है। Regex तब तक जारी रहेगा जब तक यह आवश्यक (bar)
समूह तक पहुंचता है और यह असफल हो जाएगा, जिस बिंदु पर रेगेक्स .*
से मिलान किए गए वर्णों को छोड़कर बैकट्रैक करेगा। यह तब तक होगा जब तक कि पहले .*
केवल '_abc_'
से मेल खाता है, जिस बिंदु पर अंतिम समूह 'bar'
से मेल खाता है। इसलिए 'abc'
की बजाय आपकी स्ट्रिंग में कैप्चर समूह में मिलान किया जा रहा है, यह गैर-कैप्चरिंग .*
में मेल खाता है। मेरी समाधान के
स्पष्टीकरण:
पहली और सबसे महत्वपूर्ण बात यह है कि _
साथ .*
को बदलने के लिए है, किसी भी मनमाने ढंग से स्ट्रिंग के मिलान करता है, तो आप जानते हैं कि विभाजक हो जाएगा कोई जरूरत नहीं है। अगली चीज़ जो हमें करने की ज़रूरत है वह यह पता लगाने के लिए है कि स्ट्रिंग का कौन सा हिस्सा वैकल्पिक है। यदि तार 'foo_abc_bar'
और 'foo_bar'
दोनों वैध हैं, तो बीच में 'abc_'
वैकल्पिक है। हम (abc_)?
का उपयोग करके इसे वैकल्पिक समूह में डाल सकते हैं। अंतिम चरण यह सुनिश्चित करना है कि हमारे पास अभी भी एक कैप्चरिंग समूह में स्ट्रिंग 'abc'
है, जिसे हम उस हिस्से को एक अतिरिक्त समूह में लपेटकर कर सकते हैं, इसलिए हम ((abc)_)?
के साथ समाप्त होते हैं। इसके बाद हमें प्रतिस्थापन को समायोजित करने की आवश्यकता है क्योंकि एक अतिरिक्त समूह है, इसलिए \1=\2=\3
के बजाय हम \1=\3=\4
का उपयोग करते हैं, \2
स्ट्रिंग 'abc_'
(यदि यह मेल खाता है) होगा। ध्यान दें कि अधिकांश रेगेक्स कार्यान्वयन में आप एक गैर-कैप्चरिंग समूह का भी उपयोग कर सकते थे और \1=\2=\3
का उपयोग करना जारी रखते थे, लेकिन sed गैर-कैप्चरिंग समूहों का समर्थन नहीं करता है।
एक वैकल्पिक:
मुझे लगता है कि regex ऊपर आपका सर्वश्रेष्ठ दांव है, क्योंकि यह सबसे स्पष्ट है (केवल सटीक तार आप में रुचि रखते हैं की भरपाई कर देंगे)। हालांकि आप लालची पुनरावृत्ति (जितना संभव हो उतने पात्रों से मेल खाते हैं) के बजाय आलसी पुनरावृत्ति (जितना संभव हो उतने पात्रों के रूप में मिलान) का उपयोग कर ऊपर वर्णित मुद्दे से बच सकते हैं।
echo 'foo_abc_bar' | sed -r 's/(foo).*?(abc).*?(bar)/\1=\2=\3/g'
स्रोत
2013-05-23 16:36:51
अभिव्यक्ति में आप '। *' का उपयोग क्यों कर रहे हैं, क्या अंडरस्कोर को किसी भी मनमानी स्ट्रिंग के साथ प्रतिस्थापित किया जा सकता है? –