AWK में एक नियमित अभिव्यक्ति के लालच को कैसे कम करें?


14

मैं गैर-लालची पैटर्न (नियमित अभिव्यक्ति) से मेल खाना चाहता हूं awk। यहाँ एक उदाहरण है:

echo "@article{gjn, Author =   {Grzegorz J. Nalepa}, " | awk '{ sub(/@.*,/,""); print }'

क्या एक नियमित अभिव्यक्ति लिखना संभव है जो छोटी स्ट्रिंग का चयन करता है?

@article{gjn,

इस लंबे तार के बजाय ?:

@article{gjn, Author =   {Grzegorz J. Nalepa},

मैं यह परिणाम प्राप्त करना चाहता हूं:

 Author =   {Grzegorz J. Nalepa},



मेरे पास एक और उदाहरण है:

प्रतिध्वनि " , लेख {gjn, लेखक = {ग्रेज़गोरेज़ जे नाल्पा}," | awk '{उप (/ , [^,] *, /, ""); प्रिंट} '
      ^ ↑ ^ ^ ^ ^ ^ ^ ^

ध्यान दें कि मैंने @वर्णों को अल्पविराम ( ,) वर्ण में इनपुट स्ट्रिंग और नियमित अभिव्यक्ति (और भी परिवर्तित ) दोनों की पहली स्थिति में बदल दिया .*है [^,]*। क्या एक नियमित अभिव्यक्ति लिखना संभव है जो छोटी स्ट्रिंग का चयन करता है?

, Author =   {Grzegorz J. Nalepa},

लंबी स्ट्रिंग के बजाय ?:

,article{gjn, Author =   {Grzegorz J. Nalepa},

मैं यह परिणाम प्राप्त करना चाहता हूं:

,article{gjn

4
बस के रूप में मजबूत HTML पार्सिंग के लिए regex अपर्याप्त हैं, वे शायद इस तरह के संदर्भ-संवेदनशील व्याकरण पार्सिंग करने में सक्षम नहीं होंगे। हालाँकि, यदि आपका इनपुट का सेट काफी प्रतिबंधित और सुव्यवस्थित है, तो आप रेगेक्स से दूर होने में सक्षम हो सकते हैं जब तक आप घोषणा करते हैं कि आपके प्रतिबंध क्या हैं। उदाहरण के लिए आप Authorएक अल्पविराम और व्हाट्सएप का अनुसरण कर सकते हैं , उसके बाद व्हाट्सएप और उसके =बाद व्हाट्सएप और उसके {बाद कोई भी गैर- }पीछा किया जा सकता है }, हालांकि इसके लिए (अन्य चीजों के अलावा) आपको {}उस = { ... }हिस्से के अंदर घोंसला नहीं बनाना चाहिए ।
jw013

@ jw013, आपकी व्याख्या के लिए धन्यवाद। फिर भी मैं अन्य उपयोगकर्ताओं के सुझावों का इंतजार करूंगा।
अब

जवाबों:


18

यदि आप उसके बाद @पहली बार का चयन करना चाहते हैं ,, तो आपको इसे निर्दिष्ट करने की आवश्यकता है@[^,]*,

इसके @बाद *गैर-अल्पविराम ( [^,]) के बाद किसी भी संख्या ( ) का अल्पविराम ( ,) होता है।

यह दृष्टिकोण समान के रूप में काम करता है @.*?,, लेकिन जैसी चीजों के लिए नहीं @.*?string, यही वह जगह है जहां एक के बाद एक चरित्र की तुलना में अधिक है। एक चरित्र की उपेक्षा करना आसान है, लेकिन regexps में स्ट्रिंग की उपेक्षा करना अधिक कठिन है

एक अलग दृष्टिकोण आपके इनपुट को stringएक चरित्र के साथ बदलने या प्रीपेन्ड करने के लिए है जो अन्यथा आपके इनपुट में नहीं होता है:

gsub(/string/, "\1&") # pre-process
gsub(/@[^\1]*\1string/, "")
gsub(/\1/, "") # revert the pre-processing

यदि आप इस बात की गारंटी नहीं दे सकते हैं कि इनपुट में आपका प्रतिस्थापन चरित्र ( \1ऊपर) नहीं होगा, तो एक दृष्टिकोण भागने वाले तंत्र का उपयोग करना है:

gsub(/\1/, "\1\3") # use \1 as the escape character and escape itself as \1\3
                   # in case it's present in the input
gsub(/\2/, "\1\4") # use \2 as our maker character and escape it
                   # as \1\4 in case it's present in the input
gsub(/string/, "\2&") # mark the "string" occurrences

gsub(/@[^\2]*\2string/, "")

# then roll back the marking and escaping
gsub(/\2/, "")
gsub(/\1\4/, "\2")
gsub(/\1\3/, "\1")

वह निश्चित strings के लिए काम करता है लेकिन इसके समकक्ष के लिए मनमाने ढंग से rexxps के लिए नहीं @.*?foo.bar


अच्छी प्रतिक्रिया के लिए बहुत-बहुत धन्यवाद। अपने संपादन में मैंने अभी तक एक और उदाहरण (मेरा संपादन देखें) पूछा।
अब

6

awkगैर-लालची मैचों को करने में असमर्थता के लिए पहले से ही कई अच्छे उत्तर प्रदान कर रहे हैं , इसलिए मैं पर्ल कॉन्टेबल रेगुलर एक्सप्रेशंस (पीसीआरई) का उपयोग करके इसे करने के लिए वैकल्पिक तरीके से कुछ जानकारी प्रदान कर रहा हूं । ध्यान दें कि अधिकांश सरल "मैच और प्रिंट" awkस्क्रिप्ट को आसानी perlसे -nकमांड-लाइन विकल्प का उपयोग करके फिर से लागू किया जा सकता है, और अधिक जटिल स्क्रिप्ट को a2p Awk के साथ पर्ल अनुवादक में परिवर्तित किया जा सकता है ।

पर्ल में एक गैर-लालची ऑपरेटर होता है जिसे पर्ल स्क्रिप्ट और पीसीआरई का उपयोग करने वाली किसी भी चीज़ में इस्तेमाल किया जा सकता है। उदाहरण के लिए, GNU grep के -Pविकल्प में भी लागू किया गया ।

PCRE पर्ल के नियमित भावों के समान नहीं है , लेकिन यह बहुत करीब है। यह कई कार्यक्रमों के लिए एक नियमित अभिव्यक्ति पुस्तकालय का एक लोकप्रिय विकल्प है, क्योंकि यह बहुत तेज़ है, और विस्तारित नियमित अभिव्यक्तियों के लिए पर्ल एन्हांसमेंट बहुत उपयोगी हैं।

से perlre (1) आदमी पेज:

   By default, a quantified subpattern is "greedy", that is, it will match
   as many times as possible (given a particular starting location) while
   still allowing the rest of the pattern to match.  If you want it to
   match the minimum number of times possible, follow the quantifier with
   a "?".  Note that the meanings don't change, just the "greediness":

       *?        Match 0 or more times, not greedily
       +?        Match 1 or more times, not greedily
       ??        Match 0 or 1 time, not greedily
       {n}?      Match exactly n times, not greedily (redundant)
       {n,}?     Match at least n times, not greedily
       {n,m}?    Match at least n but not more than m times, not greedily

3

यह एक पुरानी पोस्ट है, लेकिन निम्नलिखित जानकारी दूसरों के लिए उपयोगी हो सकती है।

गैर-लालची आरई मिलान करने के लिए, जागने में, एक तरह से, अलग-अलग क्रूड है। मूल विचार मैच (स्ट्रिंग, आरई) फ़ंक्शन का उपयोग करना है, और जब तक मैच विफल नहीं होता है, तब तक स्ट्रिंग के आकार को उत्तरोत्तर कम करते हैं, जैसे (अप्रयुक्त):

if (match(string, RE)) {
    rstart = RSTART
    for (i=RLENGTH; i>=1; i--)
        if (!(match(substr(string,1,rstart+i-1), RE))) break;
    # At this point, the non-greedy match will start at rstart
    #  for a length of i+1
}

2

सामान्य अभिव्यक्तियों के लिए, इसका उपयोग गैर-लालची मैच के रूप में किया जा सकता है:

function smatch(s, r) {
    if (match(s, r)) {
        m = RSTART
        do {
            n = RLENGTH
        } while (match(substr(s, m, n - 1), r))
        RSTART = m
        RLENGTH = n
        return RSTART
    } else return 0
}

मैं @ जिममेलर के जवाब के आधार पर इसका उपयोग कर रहा हूं। smatchजैसा व्यवहार करता हैmatch , लौटकर:

वह स्थिति s जहाँ नियमित अभिव्यक्ति rहोती है, या 0 नहीं होने पर। चर RSTARTऔर RLENGTHमिलान स्ट्रिंग की स्थिति और लंबाई के लिए सेट कर रहे हैं।


1

गैर-लालची मिलान करने के लिए जागने का कोई तरीका नहीं है। आप वांछित आउटपुट प्राप्त करने में सक्षम हो सकते हैं, हालांकि। sch का सुझाव उस लाइन के लिए काम करेगा। यदि आप अल्पविराम पर भरोसा नहीं कर सकते हैं, लेकिन "लेखक" हमेशा आप क्या चाहते हैं की शुरुआत है, तो आप यह कर सकते हैं:

awk '{ sub(/@.*Author/,"Author"); print }'

यदि लेखक के पूर्ववर्ती वर्णों की संख्या हमेशा समान होती है, तो आप ऐसा कर सकते हैं:

awk '{ sub(/@.{21}/,""); print }'

आपको बस यह जानना होगा कि पूरे सेट में आपका डेटा कैसा दिखता है।


0

एक रास्ता जरूर होता है। दिए गए समस्या को विभाजक के रूप में अल्पविराम का उपयोग करके आसानी से हल किया जा सकता है।

echo "@article{gjn2010jucs, Author =   {Grzegorz J. Nalepa}, " |
awk -F, '{sub(/^[ \t]/, "", $2); print $2}'

जब खेतों की संख्या कुछ भिन्न होती है तो आमतौर पर बेहतर की जरूरत होती है। ऐसे मामले में स्टॉप शब्द ढूंढना अक्सर बंद हो जाता है, क्योंकि आप उनका उपयोग करके लाइन से कुछ भी काट सकते हैं। उदाहरण के संदर्भ में यहाँ मैं क्या रोक शब्दों से मतलब है।

echo "@article{gjn2010jucs, Author =   {Grzegorz J. Nalepa}, " |
awk  '{sub(/.*Author/, "Author", $0); sub(/},.*/, "}", $0); print $0}'

0

मुझे पता है यह एक पुरानी पोस्ट है। लेकिन यहाँ केवल ओपी के रूप में अनुरोध के रूप में awk का उपयोग करने के लिए कुछ है:
A = @ लेख {gjn2010jucs, लेखक = {Grzegorz J. Nalepa},
गूंज $ A | awk 'sub (/ @ [^,] / /, ")" "' '

आउटपुट:
लेखक = {ग्रेज़गोरेज़ जे नाल्पा},


1
यह उत्तर लगभग पाँच कारणों से गलत है।
स्कॉट

3
क्या आप मुझे समझने में मदद कर सकते हैं कि क्या गलत है? आउटपुट अनुरोध के अनुरूप है। यह समझने की कोशिश करना कि उत्तर सही क्यों है / सही नहीं है।
विनीत NAIR
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.