क्या कोई फ़ील्ड है जो नियमित अभिव्यक्ति में उपयोग किए जाने वाले सटीक फ़ील्ड विभाजक FS को संग्रहीत करता है, जो RS के लिए RT के बराबर है?

Jan 04 2021

में जीएनयू Awk के 4.1.2 रिकॉर्ड विभाजन के साथgawk हम पढ़ सकते हैं:

जब RSएकल वर्ण RTहोता है, तो एकल वर्ण होता है। हालांकि, जब RSएक नियमित अभिव्यक्ति होती है, RTतो वास्तविक इनपुट पाठ होता है जो नियमित अभिव्यक्ति से मेल खाता है।

यह चर कुछ मामलोंRT में बहुत उपयोगी है ।

इसी तरह, हम क्षेत्र विभाजक के रूप में एक नियमित अभिव्यक्ति सेट कर सकते हैं। उदाहरण के लिए, यहां हम इसे ""; या "|":

$ gawk -F';' '{print NF}' <<< "hello;how|are you" 2 # there are 2 fields, since ";" appears once $ gawk -F'[;|]' '{print NF}' <<< "hello;how|are you"
3  # there are 3 fields, since ";" appears once and "|" also once

हालाँकि, यदि हम डेटा को फिर से पैक करना चाहते हैं, तो हमारे पास यह जानने का कोई तरीका नहीं है कि दो क्षेत्रों के बीच कौन सा विभाजक दिखाई दिया। इसलिए अगर पिछले उदाहरण में मैं खेतों से लूप लेना चाहता हूं और उन्हें एक साथ फिर से प्रिंट करना चाहता हूं FS, तो यह हर मामले में पूरी अभिव्यक्ति को प्रिंट करता है:

$ gawk -F'[;|]' '{for (i=1;i<=NF;i++) printf ("%s%s", $i, FS)}' <<< "hello;how|are you"
hello[;|]how[;|]are you[;|]  # a literal "[;|]" shows in the place of FS

क्या उन क्षेत्रों में से प्रत्येक को विभाजित करने के लिए उपयोग किए जाने वाले विशिष्ट फ़ील्ड विभाजक का उपयोग करने के लिए फ़ील्ड को "रीपैक" करने का एक तरीका है, उसी तरह आरटी क्या करने की अनुमति देगा?

(प्रश्न में दिए गए उदाहरण सरल हैं, लेकिन केवल बिंदु दिखाने के लिए)

जवाब

8 anubhava Jan 04 2021 at 16:34

क्या उन क्षेत्रों में से प्रत्येक को विभाजित करने के लिए उपयोग किए जाने वाले विशिष्ट क्षेत्र विभाजक का उपयोग करके "रीपैक" करने का एक तरीका है

का उपयोग करना gnu-awk split()है कि आपूर्ति की regex का उपयोग कर सीमांकक का मिलान नहीं हुआ के लिए एक अतिरिक्त 4 पैरामीटर है:

s="hello;how|are you"
awk 'split($0, flds, /[;|]/, seps) {for (i=1; i in seps; i++) printf "%s%s", flds[i], seps[i]; print flds[i]}' <<< "$s"

hello;how|are you

अधिक पठनीय संस्करण:

s="hello;how|are you"
awk 'split($0, flds, /[;|]/, seps) { for (i=1; i in seps; i++) printf "%s%s", flds[i], seps[i] print flds[i] }' <<< "$s"

3 पैरामीटर में उपयोग किए गए नियमित अभिव्यक्ति द्वारा मेल खाने वाले पाठ की एक सरणी को स्टोर करने वाले 4 वें sepsपैरामीटर पर ध्यान दें ।split/[;|]/

बेशक, यह उतना छोटा और सरल नहीं है RS, ORSऔर RT, जिसे इस प्रकार लिखा जा सकता है:

awk -v RS='[;|]' '{ORS = RT} 1' <<< "$s"
5 EdMorton Jan 04 2021 at 22:41

जैसा कि @anubhava का उल्लेख है , gawk है split()(और patsplit()जो FPATजैसा split()है FS- देखना हैhttps://www.gnu.org/software/gawk/manual/gawk.html#String-Functions) जो आप चाहते हैं वह करने के लिए। यदि आप POSIX awk के साथ समान कार्यक्षमता चाहते हैं तो:

$ cat tst.awk function getFldsSeps(str,flds,fs,seps, nf) { delete flds delete seps str = $0

    if ( fs == " " ) {
        fs = "[[:space:]]+"
        if ( match(str,"^"fs) ) {
            seps[0] = substr(str,RSTART,RLENGTH)
            str = substr(str,RSTART+RLENGTH)
        }
    }

    while ( match(str,fs) ) {
        flds[++nf] = substr(str,1,RSTART-1)
        seps[nf]   = substr(str,RSTART,RLENGTH)
        str = substr(str,RSTART+RLENGTH)
    }

    if ( str != "" ) {
        flds[++nf] = str
    }

    return nf
}

{
    print
    nf = getFldsSeps($0,flds,FS,seps)
    for (i=0; i<=nf; i++) {
        printf "{%d:[%s]<%s>}%s", i, flds[i], seps[i], (i<nf ? "" : ORS)
    }
}

उस क्षेत्र के ऊपर विशिष्ट हैंडलिंग पर ध्यान दें जहां फ़ील्ड विभाजक है, " "क्योंकि इसका अर्थ है कि अन्य सभी फ़ील्ड विभाजक मानों से 2 चीज़ें अलग हैं:

  1. फ़ील्ड वास्तव में किसी भी सफेद स्थान की जंजीरों से अलग होती हैं, और
  2. जब $ 1 (या इस मामले में flds [1]) को पॉप्युलेट किया जा रहा हो, तो श्वेत स्थान को अनदेखा किया जाना चाहिए और ताकि सफ़ेद स्थान, अगर मौजूद हो, तो हमारे उद्देश्यों के लिए seps [0] में कैप्चर किया जाए क्योंकि [n] संबद्ध है इस flds के साथ [n] कि यह पहले से है।

उदाहरण के लिए, इन 3 इनपुट फ़ाइलों पर ऊपर चल रहा है:

$ head file{1..3}
==> file1 <==
hello;how|are you

==> file2 <==
hello how are_you

==> file3 <==
    hello how are_you

हम निम्नलिखित आउटपुट प्राप्त करेंगे, जहां प्रत्येक फ़ील्ड को फ़ील्ड संख्या के रूप में प्रदर्शित किया जाता है, फिर फ़ील्ड के भीतर [...]विभाजक <...>, सभी के भीतर {...}(ध्यान दें कि seps[0]IFF FS आबादी है " "और रिकॉर्ड सफेद स्थान से शुरू होता है):

$ awk -F'[,|]' -f tst.awk file1
hello;how|are you
{0:[]<>}{1:[hello;how]<|>}{2:[are you]<>}

$ awk -f tst.awk file2 hello how are_you {0:[]<>}{1:[hello]< >}{2:[how]< >}{3:[are_you]<>} $ awk -f tst.awk file3
    hello how are_you
{0:[]<    >}{1:[hello]< >}{2:[how]< >}{3:[are_you]<>}
3 RamanSailopal Jan 04 2021 at 16:51

विभाजित करने के लिए एक वैकल्पिक विकल्प फ़ील्ड विभाजकों को खोजने और उन्हें एक सरणी में पढ़ने के लिए मैच का उपयोग करना है:

awk -F'[;|]' '{
    str=$0; # Set str to the line while (match(str,FS)) { # Loop through rach match of the field separator map[cnt+=1]=substr(str,RSTART,RLENGTH); # Create an array of the field separators str=substr(str,RSTART+RLENGTH) # Set str to the rest of the string after the match string } for (i=1;i<=NF;i++) { printf "%s%s",$i,map[i] # Loop through each record, printing it along with the field separator held in the array map.
    } 
    printf "\n" 
   }' <<< "hello;how|are you"