2013-05-23 3 views
5

मेरे पास दो स्ट्रिंग हैं, foo_bar और foo_abc_bar कहें। मैं उन दोनों से मेल खाना चाहता हूं, और यदि पहला मैच मेल खाता है तो मैं इसे = साइन पर जोर देना चाहूंगा। तो, मेरा अनुमान था:क्यों sed एक वैकल्पिक समूह मुद्रित नहीं करता है?

echo 'foo_abc_bar' | sed -r 's/(foo).*(abc)?.*(bar)/\1=\2=\3/g' 
> foo==bar 

या

echo 'foo_abc_bar' | sed -r 's/(foo).*((abc)?).*(bar)/\1=\2=\3/g' 
> foo== 

लेकिन उनमें से कोई भी काम के रूप में उत्पादन के ऊपर से पता चलता।

मैं एक वैकल्पिक समूह को कैसे निर्दिष्ट कर सकता हूं जो स्ट्रिंग में है या अगर नहीं तो बस मेल खाएगा?

+0

अभिव्यक्ति में आप '। *' का उपयोग क्यों कर रहे हैं, क्या अंडरस्कोर को किसी भी मनमानी स्ट्रिंग के साथ प्रतिस्थापित किया जा सकता है? –

उत्तर

8

समाधान:

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' 
1

हो सकता है कि आप बस इस्तेमाल कर सकते हैं:: आप .* करने के लिए .*? बदलकर ऐसा कर सकते हैं, तो अपनी अभिव्यक्ति कुछ इस तरह दिखेगा

echo 'foo_abc_bar' | sed -r 's/(foo|bar|abc)_?/\1=/g' 
echo 'foo_bar' | sed -r 's/(foo|bar|abc)_?/\1=/g' 

> foo=abc=bar= 
> foo=bar= 

इस से बचा जाता है foo==bar आप foo_bar और मैं साथ मिल कभी-कभी मैच के बाद मैच से पहले = डालकर जोर देने के लिए थोड़ा अजीब पाया गया।

संबंधित मुद्दे