सभी लाइनों को एक साथ कैसे मिलाएं जो पैटर्न से मेल खाते हैं?


12

मैं केवल उन लाइनों के लिए एक साथ लाइनों में शामिल होना चाहता हूं जिनके कुछ निश्चित पैटर्न (जैसे ;) हैं, हालांकि g/;/jइसका उपयोग करते समय यह अपेक्षित रूप से काम नहीं करता है जब तक कि दो बार नहीं बुलाया जाता है।

उदाहरण के लिए निम्नलिखित सामग्री:

a
1;
2;
3;
4;
5;
b
6;
7;
8;
9;
c

उपयोग करते समय: :g/;/jआउटपुट है:

a
1; 2;
3; 4;
5; b
6; 7;
8; 9;
c

या :g/;/-jदेता है:

a 1; 2; 3; 4; 5;
b 6; 7; 8; 9;
c

के साथ इसी तरह: :g/;\_.\{-};/j

मेरा अपेक्षित आउटपुट है:

a 
1; 2; 3; 4; 5;
b
6; 7; 8; 9;
c

या ऐसा ही कुछ, इसलिए पैटर्न वाली सभी लाइनें एक साथ जुड़ जाती हैं।

यह कैसे प्राप्त किया जा सकता है?


3
FWIW, :g/;/jकाम नहीं करता है क्योंकि यह दो पास में किया जाता है: पहले बफर को स्कैन किया जाता है, फिर कमांड को मिलान लाइनों पर लागू किया जाता है।
रोमेनिल

जवाबों:


12

समस्या की संभावित व्याख्या

मुझे लगता है कि :g/;/jकाम नहीं करने का कारण यह है क्योंकि :gकमांड 2-पास एल्गोरिथ्म के साथ काम करता है:

  • पहले पास के दौरान यह पैटर्न वाली लाइनों को चिह्नित करता है ;
  • दूसरे पास के दौरान यह चिह्नित लाइनों पर संचालित होता है

दूसरे पास के दौरान, :gलाइन के 1;साथ लाइन जुड़ती है 2;क्योंकि 1;पहले पास के दौरान चिह्नित किया गया था। हालाँकि मुझे संदेह है (निश्चित नहीं) कि यह 1; 2;साथ नहीं जुड़ता 3;क्योंकि लाइन 2;अब मौजूद नहीं है, इसकी सामग्री को उस लाइन के साथ मिला दिया गया है 1;जो पहले ही संसाधित हो चुकी है।

तो :gअगली पंक्ति के लिए लग रहा है जो पहली पास ( 3;) के दौरान चिह्नित किया गया था और इसे निम्नलिखित एक ( 4;) के साथ जोड़ता है । उसके बाद समस्या दोहराई जाती है, यह 3; 4;साथ नहीं जुड़ सकता 5;क्योंकि लाइन 4;अब मौजूद नहीं है।

समाधान 1 (विमस्क्रिप्ट के साथ)

हो सकता है कि आप किसी फ़ंक्शन को कॉल कर सकें, जब ;यह पाया जाए कि पिछली पंक्ति में अर्धविराम शामिल है या नहीं

function! JoinLines()
    if getline(line('.')-1) =~ ';'
        .-1join
    endif
endfunction

फिर निम्न वैश्विक कमांड का उपयोग करें:

:g/;/call JoinLines()

या एक समारोह के बिना:

:g/;/if getline(line('.')-1) =~ ';' | -j | endif

समाधान 2 (विस्मार्क रहित)

:g/;/.,/^[^;]*$/-1j

जब भी वैश्विक कमांड :gपैटर्न को ;निष्पादित करता है तो वह कमांड को निष्पादित करता है: .,/^[^;]*$/-1j

इसे इस तरह तोड़ा जा सकता है:

:g/pattern/a,bj

कहाँ पे :

pattern = ;
a       = .           = number of current line
b       = /^[^;]*$/-1 = number of next line without any semicolon minus one

b इस तरह आगे टूट सकता है:

/    = look for the number of the next line matching the following pattern
^    = a beginning of line
[^;] = then any character except a semicolon
 *   = the last character can be repeated 0 or more times
 $   = an end of line
 /   = end of pattern
 -1  = removes one to the number you just got

jपूर्व कमान का संक्षिप्त रूप है, :joinजो अन्य पूर्व कमांडों की तरह एक सीमा से पहले हो सकता है।
: यहाँ यह सीमा से पहले है .,/^[^;]*$/-1( a,b)
एक सीमा प्रपत्र इस प्रकार a,bजहां aऔर bआम तौर पर 2 लाइन नंबर हैं, और आप लाइनों जिनकी संख्या के बीच है के एक समूह पर संचालित करने के लिए अनुमति देता है aऔर bसिर्फ एक के बजाय,।

तो jकमांड वर्तमान एक ( a) और अगले एक के बीच सभी लाइनों को जोड़ता है जिसमें कोई अर्धविराम ऋण एक ( b) नहीं है।

अधिक जानकारी के लिए देखें:

:help :global
:help :join
:help :range

2

मैं एक वैश्विक खोज के साथ हर समय समान रूप से जुड़ता हूं और प्रतिस्थापित करता हूं:

एस /; \ N /; /

\n मेल खाता है।

रिक्त लाइनों को खोजने और हटाने के लिए:

s / ^ $ \ N //

मुझे यकीन नहीं है कि क्यों, लेकिन यदि आप एक नई लाइन सम्मिलित करना चाहते हैं तो आपको इसका उपयोग करना होगा \r


sअकेले ही एक लाइन के लिए काम करेगा, इसे वैश्विक बनाने के लिए, आपको उपयोग करने की आवश्यकता है %s, लेकिन फिर यह लगभग सभी लाइनों को जोड़ देगा, जिसमें गैर ;लाइनें भी शामिल हैं
kenorb

2
@kenorb Ehm नहीं, मुझे लगता है कि आप :sजो चाहते हैं उसके लिए आप वास्तव में कमांड का उपयोग कर सकते हैं। मुझे लगता है कि यह %s/;\n\(.*;\)\@=/;/वही करता है जो आपको चाहिए।
क्रिश्चियन ब्रेबांट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.