किसी फ़ाइल में केवल पैटर्न की केवल Nth घटना को कैसे बदलें?


10

sedकमांड का उपयोग करके फ़ाइल में स्ट्रिंग की तीसरी घटना को कैसे बदलें ।

उदाहरण:

की केवल तीसरी घटना बदलें isकरने के लिए usफ़ाइल में।

मेरी इनपुट फ़ाइल में है:

hai this is linux.
hai this is unix.
hai this is mac.
hai this is unchanged.

मुझे उम्मीद है कि आउटपुट है:

hai this is linux.
hai thus is unix.
hai this is mac.
hai this is unchanged.

3
इनपुट और आउटपुट समान हैं।
हौके लागिंग

4
sedनौकरी के लिए सही उपकरण नहीं है।
कोरोबा

@don_crissti मैंने इसे ठीक किया। ओपी ने प्रारूपण साधनों का उपयोग नहीं किया था (वैसे, सुरेशकुमार, अपने सवालों को संपादित करने में मदद के लिए यहां देखें ) और क्रमिक संपादकों ने गलत समझा था कि वह क्या चाहते थे।
terdon

जवाबों:


11

यह बहुत आसान है perl

3 आरडी घटना को बदलने के लिए :

perl -pe 's{is}{++$n == 3 ? "us" : $&}ge'

हर 3 rd घटना को बदलने के लिए :

perl -pe 's{is}{++$n % 3 ? $& : "us"}ge'

3

जब प्रति पंक्ति केवल एक बार प्रतिस्थापन स्ट्रिंग होती है, तो आप विभिन्न उपयोगिताओं को जोड़ सकते हैं।
जब इनपुट फ़ाइल "इनपुट" में होता है और आप "हमें" द्वारा "प्रतिस्थापित" कर रहे हैं, तो आप उपयोग कर सकते हैं

LINENR=$(cat input | grep -n " is " | head -3 | tail -1 | cut -d: -f1)
cat input | sed ${LINENR}' s/ is / us /'

प्रश्न में उदाहरण में, isप्रति पंक्ति एक से अधिक हैं ।
terdon

मुझे लगा कि आप रिक्त स्थान के साथ "है" के लिए देख रहे हैं। मैं अपने उत्तर को संपादित कर सकता था जैसे कि @ जिमीज का इस्तेमाल किया गया था, लेकिन मेरा समाधान उनके लिए बहुत ही हीन हो जाएगा।
वाल्टर ए

मैं पूछने वाला नहीं हूं :)। मैं एक ही बात है, जिसके कारण मैं अपने जवाब upvoted था सोचा, लेकिन अगर आप प्रश्न के मूल संस्करण को देखने के ( "पहले संपादित एक्स मिनट" लिंक पर क्लिक करें) आप देखेंगे ओपी उम्मीद है कि है में इस इस प्रकार परिवर्तित किया जा सकता है । वैसे, वहाँ बिल्ली की कोई आवश्यकता नहीं है
terdon

2

नीचे दी गई स्क्रिप्ट ( GNU sed सिंटैक्स का उपयोग करके ) आउटपुट के लिए नहीं संपादन के लिए प्रयोग करने योग्य है क्योंकि यह वांछित प्रतिस्थापन के बाद प्रिंट लाइनों को रोक देता है:

sed -i '/is/{: 1 ; /\(.*is\)\{3\}/!{N;b1} ; s/is/us/3 ; q}' text.file

यदि आपका चोराबा निर्णय आपको पसंद आता है, तो आप इसे संशोधित कर सकते हैं

sed '/is/{:1 ; /\(.*is\)\{3\}/!{N;b1} ; s/is/us/3 ; :2 ; n ; $!b2}' text.file

जो सभी लाइनों को आउटपुट करता है

या आपको पैटर्न स्पेस में सभी लाइनें डालनी होंगी (मेमोरी में इसलिए साइज़ लिमिट से सावधान रहें) और प्रतिस्थापन करें

sed ': 1 ; N ; $!b1 ; s/is/us/3 ' text.file

2

आप इसके लिए उपयोग कर सकते हैं sedयदि पूर्व में नई वर्णमाला को किसी अन्य वर्ण में बदल दिया जाता है, जैसे:

tr '\n' '\000' | sed 's/is/us/3' | tr '\000' '\n'

और शुद्ध (GNU) के साथ भी ऐसा ही है sed:

sed ':a;N;$!ba;s/\n/\x0/g;s/is/us/3;s/\x0/\n/g'

( sednewline प्रतिस्थापन बेशर्मी से https://stackoverflow.com/a/1252191/4488514 से चुराया गया )


यदि आप GNU sedविशिष्ट सिंटैक्स का उपयोग करने जा रहे हैं , तो आप भी उपयोग कर सकते हैं sed -z 's/is/us/3'
स्टीफन चेजलस

@ स्टीफनचेज़ेलस -zको कुछ नया फीचर होना चाहिए, मेरे GNU sed version 4.2.1पास इस विकल्प के बारे में कुछ भी नहीं है।
जिमीज

1
4.2.2 (2012) में जोड़ा गया। अपने दूसरे समाधान में, आपको रूपांतरण की आवश्यकता नहीं है \x0
स्टीफन चेजलस

एडिट के बारे में क्षमा करें। मैंने प्रश्न का मूल संस्करण नहीं देखा था और किसी ने इसे गलत समझा था और गलत लाइन को संपादित किया था। मैं पिछले संस्करण पर लौट आया।
terdon

1
p='[:punct:]' s='[:space:]'
sed -Ee'1!{/\n/!b' -e\}            \
     -e's/(\n*)(.*)/ \2 \1/'       \
     -e"s/is[$p]?[$s]/\n&/g"       \
     -e"s/([^$s])\n/\1/g;1G"       \
-e:c -e"s/\ni(.* )\n{3}/u\1/"      \
     -e"/\n$/!s/\n//g;/\ni/G"      \
     -e's//i/;//tc'                \
     -e's/^ (.*) /\1/;P;$d;N;D'

sedबस थोड़ा सा isएक लाइन से दूसरी में होने वाली घटनाओं का एक हिस्सा होता है। इसे मज़बूती से isआपके द्वारा फेंके जाने के अनुसार प्रति पंक्ति के रूप में संभालना चाहिए , और इसे करते समय इसे पुरानी लाइनों को बफर करने की आवश्यकता नहीं है - यह सिर्फ हर एक के लिए एक नई लाइन वर्ण को बरकरार रखता है isजो उसका सामना करता है जो दूसरे शब्द का हिस्सा नहीं है।

यह एक फ़ाइल में केवल तीसरी घटना को संशोधित करेगा - और यह प्रति पंक्ति में गणना करेगा। इसलिए यदि कोई फाइल दिखती है:

1. is is isis
2. is does

... यह छपेगा ...

1. is is isis
2. us does

यह पहले हर पंक्ति के सिर और पूंछ पर एक स्थान डालकर किनारे के मामलों को संभालता है। इससे शब्द सीमाओं का पता लगाना थोड़ा आसान हो जाता है।

इसके बाद isएक \nशून्य डालने से पहले वैध ईएस के लिए लगता है कि एक जगह से isपहले शून्य या एक विराम चिह्न वर्णों के सभी घटनाओं से पहले। यह एक और पास करता है और सभी \newlines को हटा देता है जो तुरंत एक नहीं-स्थान चरित्र से पहले होते हैं। पीछे छोड़ दिया यह मार्कर से मिलान करेगा is.और isनहीं बल्कि thisया ?is

यह अगली बार प्रत्येक मार्कर को स्ट्रिंग की पूंछ पर इकट्ठा करता है - \niएक लाइन पर हर मैच के लिए यह स्ट्रिंग की पूंछ के लिए एक \nइवलाइन जोड़ता है और इसे iया तो साथ बदल देता है u। यदि \nस्ट्रिंग की पूंछ पर इकट्ठी एक पंक्ति में 3 इवलाइन हैं तो यह यू का उपयोग करता है - और मैं। पहली बार एयू का उपयोग किया जाता है यह भी अंतिम है - प्रतिस्थापन एक अनंत लूप को सेट करता है जो नीचे get line, print line, get line, print line,और इतने पर उबलता है ।

प्रत्येक कोशिश लूप चक्र के अंत में यह सम्मिलित स्थानों को साफ करता है, पैटर्न स्पेस में केवल पहली होने वाली न्यूलाइन तक प्रिंट करता है, और फिर से जाता है।

मैं lलूप के सिर पर एक ook कमांड में जोड़ूंगा:

l; s/\ni(.* )\n{9}/u\1/...

... और इस इनपुट के साथ काम करने पर एक नज़र डालें:

hai this is linux.
hai this is unix.


hai this is mac.
hai this is unchanged is.

... तो यहाँ यह क्या करता है:

 hai this \nis linux. \n$        #behind the scenes
hai this is linux.               #actually printed
 hai this \nis unix. \n\n$       #it builds the marker string
hai this is unix.
  \n\n\n$                        #only for lines matching the

  \n\n\n$                        #pattern - and not otherwise.

 hai this \nis mac. \n\n\n$      #here's the match - 3 ises so far in file.
hai this us mac.                 #printed
hai this is unchanged is.        #no look here - this line is never evaled

यह संभवत is: प्रति पंक्ति अधिक एसेंस के साथ अधिक समझ में आता है :

nthword()(  p='[:punct:]' s='[:space:]'         
    sed -e '1!{/\n/!b' -e\}             \
        -e 's/\(\n*\)\(.*\)/ \2 \1/'    \
        -e "s/$1[$p]\{0,1\}[$s]/\n&/g"  \
        -e "s/\([^$s]\)\n/\1/g;1G;:c"   \
        -e "${dbg+l;}s/\n$1\(.* \)\n\{$3\}/$2\1/" \
        -e '/\n$/!s/\n//g;/\n'"$1/G"    \
        -e "s//$1/;//tc" -e 's/^ \(.*\) /\1/'     \
        -e 'P;$d;N;D'
)        

यह व्यावहारिक रूप से एक ही बात है, लेकिन w / POSIX BRE और अल्पविकसित तर्क हैंडलिंग लिखा है।

 printf 'is is. is? this is%.0s\n' {1..4}  | nthword is us 12

... हो जाता है ...

is is. is? this is
is is. is? this is
is is. is? this us
is is. is? this is

... और अगर मैं सक्षम हूं ${dbg}:

printf 'is is. is? this is%.0s\n' {1..4}  | 
dbg=1 nthword is us 12

... हम इसे पुन: देख सकते हैं ...

 \nis \nis. \nis? this \nis \n$
 is \nis. \nis? this \nis \n\n$
 is is. \nis? this \nis \n\n\n$
 is is. is? this \nis \n\n\n\n$
is is. is? this is
 \nis \nis. \nis? this \nis \n\n\n\n\n$
 is \nis. \nis? this \nis \n\n\n\n\n\n$
 is is. \nis? this \nis \n\n\n\n\n\n\n$
 is is. is? this \nis \n\n\n\n\n\n\n\n$
is is. is? this is
 \nis \nis. \nis? this \nis \n\n\n\n\n\n\n\n\n$
 is \nis. \nis? this \nis \n\n\n\n\n\n\n\n\n\n$
 is is. \nis? this \nis \n\n\n\n\n\n\n\n\n\n\n$
 is is. is? this \nis \n\n\n\n\n\n\n\n\n\n\n\n$
is is. is? this us
is is. is? this is

क्या आपको एहसास हुआ कि आपका उदाहरण "आइसिस" है?
flarn2006

@ flarn2006 - im बहुत यकीन है कि यह है कहते हैं।
mikeserv

0

यहाँ एक तार्किक समाधान है कि का उपयोग करता है है sedऔर trलेकिन काम करने के लिए इसके लिए एक लिपि में लिखा जाना चाहिए। नीचे दिया गया कोड कमांड में निर्दिष्ट शब्द की हर तीसरी घटना को प्रतिस्थापित करता है sed। बदलें i=3के साथ i=nकिसी के लिए यह काम करने के लिए n

कोड:

# replace new lines with '^' character to get everything onto a single line
tr '\n' '^' < input.txt > output.txt

# count number of occurrences of the word to be replaced
num=`grep -o "apple" "output.txt" | wc -l`

# in successive iterations, replace the i + (n-1)th occurrence
n=3
i=3
while [ $i -le $num ]
do
    sed -i '' "s/apple/lemon/${i}" 'output.txt'
    i=$(( i + (n-1) ))
done

# replace the '^' back to new line character
tr '^' '\n' < output.txt > tmp && mv tmp output.txt


यह क्यों काम करता है:

मान लीजिए कि टेक्स्ट फाइल है a b b b b a c a d a b b b a b e b z b s b a b

  • जब n = 2: हम हर दूसरी घटना को बदलना चाहते हैं b

    • a b b b b a c a d a b b b a b e b z b s b a b
      . . ^ . ^ . . . . . . ^ . . ^ . . . ^ . ^ . ^
    • पहले हम दूसरी घटना को प्रतिस्थापित करते हैं, फिर तीसरी घटना को, फिर 4 वें, 5 वें और इसी तरह। अपने लिए यह देखने के लिए ऊपर दिखाए गए अनुक्रम में गणना करें।
  • जब n = 3: हम हर तीसरी घटना को बदलना चाहते हैं b

    • a b b b b a c a d a b b b a b e b z b s b a b
      . . . ^ . . . . . . . ^ . . . . ^ . . . . . ^
    • पहले हम तीसरी घटना को प्रतिस्थापित करते हैं, फिर 5 वें को, फिर 7 वें, 9 वें, 11 वें और इसी तरह।
  • जब n = 4: हम हर तीसरी घटना को बदलना चाहते हैं b

    • पहले हम 4 वीं घटना को प्रतिस्थापित करते हैं, फिर 7 वें, फिर 10 वें, 13 वें और इसी तरह।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.