विम में कई लाइनों (दो ब्लॉक) को मिलाएं


323

मैं Vim में लाइनों के दो ब्लॉक मर्ज करना चाहता हूं, यानी लाइनें लेना n..mऔर उन्हें लाइनों में जोड़ना a..b। यदि आप एक छद्म व्याख्या पसंद करते हैं:[a[i] + b[i] for i in min(len(a), len(b))]

उदाहरण:

abc
def
...

123
45
...

बन जाना चाहिए

abc123
def45

क्या मैन्युअल रूप से कॉपी और पेस्ट किए बिना ऐसा करने का एक अच्छा तरीका है?


तो ... आप वैकल्पिक लाइनों में शामिल होना चाहते हैं? यही है, आप लाइन xमें शामिल होने के साथ जुड़ना x+2चाहते हैं?
लार्क्स

1
नहीं, मेरे दो अलग-अलग ब्लॉक हैं। स्यूडोकोड-ईश:[a[i] + b[i] for i in min(len(a), len(b))]
थिएमस्टर

2
इसी तरह का प्रश्न (और उत्तर देखें) यहाँ देखें
NWS

जवाबों:


880

आप निश्चित रूप से एक कॉपी / पेस्ट (ब्लॉक-मोड चयन का उपयोग करके) के साथ यह सब कर सकते हैं, लेकिन मैं अनुमान लगा रहा हूं कि आप क्या चाहते हैं।

अगर आप ऐसा सिर्फ Ex कमांड से करना चाहते हैं

:5,8del | let l=split(@") | 1,4s/$/\=remove(l,0)/

बदल जाएगा

work it 
make it 
do it 
makes us 
harder
better
faster
stronger
~

में

work it harder
make it better
do it faster
makes us stronger
~

अद्यतन: इस कई उत्तोलकों के साथ एक उत्तर एक अधिक गहन व्याख्या के योग्य है।

विम में, आप |कई एक्सट्रीम कमांड को चेन कैरेक्टर ( ) का उपयोग कर सकते हैं , इसलिए ऊपर इसके बराबर है

:5,8del
:let l=split(@")
:1,4s/$/\=remove(l,0)/

कई पूर्व कमांड्स उपसर्ग तर्क के रूप में लाइनों की एक सीमा को स्वीकार करते हैं - उपरोक्त मामले 5,8में delऔर निर्दिष्ट करने 1,4से पहले कि s///कौन सी लाइनें कमांड संचालित करती हैं।

delदी गई लाइनों को हटाता है। यह एक रजिस्टर तर्क ले सकता है, लेकिन जब किसी को नहीं दिया जाता है, तो यह पंक्तियों को अनाम रजिस्टर में डंप कर देता है @", जैसे सामान्य मोड में डिलीट करता है। let l=split(@")फिर डिलीट लाइनों को डिफॉल्ट सीमांकक का उपयोग करके एक सूची में विभाजित करता है: व्हॉट्सएप। हटाए गए लाइनों में व्हाट्सएप इनपुट पर ठीक से काम करने के लिए, जैसे:

more than 
hour 
our 
never 
ever
after
work is
over
~

हम को रोकने के लिए, एक अलग सीमांकक निर्दिष्ट करने की आवश्यकता होगी दो सूची तत्वों में विभाजित किया जा रहा से "काम है": let l=split(@","\n")

अंत में, प्रतिस्थापन में s/$/\=remove(l,0)/, हम प्रत्येक पंक्ति के अंत ( $) को अभिव्यक्ति के मान से प्रतिस्थापित करते हैं remove(l,0)remove(l,0)सूची lको बदल देता है , हटा रहा है और इसके पहले तत्व को वापस कर रहा है। यह हमें हटाए गए लाइनों को उस क्रम में बदलने की अनुमति देता है जिसमें हम उन्हें पढ़ते हैं। हम बदले में हटाए गए लाइनों को रिवर्स ऑर्डर में बदलकर उपयोग कर सकते हैं remove(l,-1)


1
हम्म ... मुझे केवल एक बार एंटर दबाना है। और यह दो हिस्सों के बीच एक जगह नहीं डालेगा। यदि लाइनों पर कुछ अनुगामी स्थान है (जैसे "काम" उदाहरण में), तो वह अभी भी वहाँ रहेगा। आप s/\s*$/इसके बजाय का उपयोग करके किसी भी अनुगामी स्थान से छुटकारा पा सकते हैं s/$/
रैंप

1
स्पष्टीकरण के लिए धन्यवाद। :sil5,8del | let l=split(@") | sil1,4s/$/\=remove(l,0)/ | call histdel("/", -1) | nohlsयह और भी बेहतर लगता है क्योंकि यह चलने के बाद खोज इतिहास को साफ करता है। और यह "x अधिक / कम लाइनें" संदेश नहीं दिखाता है जो मुझे एंटर प्रेस करने की आवश्यकता है।
ThiefMaster

11
आपको लगता है कि जवाब के लिए पूर्ण vim संदर्भ चाहते हैं: :help range, :help :d, :help :let, :help split(), :help :s, :help :s\=, :help remove()
बेनोइट

16
सुनिश्चित करें कि आप जैसे लोगों को इस तरह से जवाब पोस्ट करना चाहते हैं यही कारण है कि मैं एक मॉडरेटर बन गया। अच्छा शो :)
टिम पोस्ट

1
पहले 4 वाक्यों के बाद श्वेत स्थान न होने पर समस्या है।
रेमन

58

मुद्दे को हल एक सुरुचिपूर्ण और संक्षिप्त पूर्व आदेश के संयोजन के द्वारा प्राप्त किया जा सकता :global, :moveऔर :joinआदेशों। यह मानते हुए कि लाइनों का पहला ब्लॉक बफर की पहली लाइन पर शुरू होता है, और यह कि कर्सर दूसरे ब्लॉक की पहली लाइन से पहले लाइन पर स्थित है, कमांड निम्नानुसार है।

:1,g/^/''+m.|-j!

इस तकनीक की विस्तृत व्याख्या के लिए , बॉक्स के बाहर एक समान प्रश्न " विम पेस्ट -d '' व्यवहार के बारे में मेरा उत्तर देखें "।


E16: Invalid Range- लेकिन यह वैसे भी काम करता है। 1,इसे हटाने पर त्रुटि के बिना काम करता है।
थीफमास्टर

और बहुत बुरा आप एक से अधिक जवाब स्वीकार नहीं कर सकते - अन्यथा आपका एक हरा निशान भी होगा!
ThiefMaster

3
बहुत अच्छा! मैं के बारे में पता नहीं था :moveऔर :join!, और न ही क्या ''एक श्रेणी तर्क (के रूप में मतलब :help '') और क्या +और -सीमा संशोधक के रूप में मतलब ( :help range)। धन्यवाद!
रैंप

@ThiefMaster: कमांड का उपयोग तब किया जाता है जब जुड़ने के लिए दो रेंज की लाइनें एक दूसरे से सटे हों, ताकि कर्सर शुरू में पहले ब्लॉक की अंतिम लाइन पर स्थित हो, जो तुरंत दूसरे ब्लॉक की पहली लाइन से पहले हो। (लिंक किए गए उत्तर और प्रश्न को देखें।) यदि ब्लॉक में लाइनों की संख्या भिन्न होती है, तो भी यह कमांड का उद्देश्य है, हालांकि यह उस स्थिति में एक त्रुटि संदेश देता है। एक sil!कमांड के बहाने त्रुटि संदेशों को दबा सकता है ।
ib।

2
@ आई बी: मुझे लगता है कि इस उत्तर में विस्तृत विवरण देना भी एक अच्छा विचार होगा।
ThiefMaster

44

लाइन के ब्लॉक में शामिल होने के लिए, आपको निम्नलिखित चरण करने होंगे:

  1. तीसरी पंक्ति पर जाएं: jj
  2. दृश्य ब्लॉक मोड दर्ज करें: CTRL-v
  3. लाइन के अंत में कर्सर को अलग करें (भिन्न लंबाई की लाइनों के लिए महत्वपूर्ण): $
  4. अंत में जाएं: CTRL-END
  5. ब्लॉक काटें: x
  6. पहली पंक्ति के अंत में जाएं: kk$
  7. यहाँ ब्लॉक पेस्ट करें: p

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

यहाँ आवश्यक शर्तें हैं इसलिए यह तकनीक अच्छी तरह से काम करती है:

  • प्रारंभिक ब्लॉक की सभी पंक्तियों (प्रश्न में उदाहरण में ) abcऔर defएक ही लंबाई XOR है
  • शुरुआती ब्लॉक की पहली पंक्ति सबसे लंबी है, और आप XOR के बीच के अतिरिक्त स्थानों की परवाह नहीं करते हैं
  • शुरुआती ब्लॉक की पहली पंक्ति सबसे लंबी नहीं है, और आप अंत तक अतिरिक्त स्थान बनाते हैं।

वाह, यह दिलचस्प है! मैंने कभी नहीं सोचा होगा कि यह उस तरह से काम करेगा।

13
यह काम करता है के रूप में सिर्फ इसलिए चाहते थे abcऔर defएक ही लंबाई हैं। ब्लॉक चयन हटाए गए पाठ के इंडेंट रखेगा, इसलिए यदि पाठ डालते समय कर्सर एक छोटी रेखा पर होता है, तो पंक्तियों को अक्षरों के बीच लंबे समय तक डाला जाता है - और यदि कर्सर लंबे समय तक था, तो रिक्त स्थान छोटे लोगों से जुड़ जाते हैं। एक।
इज़्काता

वास्तव में ... क्या ब्लॉक कॉपी और पेस्ट का उपयोग ठीक से करने का कोई तरीका है? यह सब करने के बाद सबसे आसान तरीका है (खासकर यदि आप किसी कारण से अधिक जटिल तरीके नहीं खोज सकते हैं)।
ThiefMaster

2
जैसे @Izkata का कहना है कि आप लंबी पंक्तियों के बीच पाठ की समस्या में भाग लेंगे। वर्कअराउंड करने के लिए, पहली पंक्ति के अंत में अधिक रिक्त स्थान जोड़कर इसे सबसे लंबा बनाएं और फिर अपने पाठ का ब्लॉक पेस्ट करें। एक बार ऐसा करने के बाद, एक से अधिक स्थानों को संपीड़ित करना उतना ही सरल है:%s/ \+/ /g
खाजा मिन्हाजुद्दीन

1
set ve=allमदद करनी चाहिए, vimdoc.sourceforge.net/htmldoc/options.html#'virtualedit ' देखें
बेन

19

यहां बताया गया है कि मैं ऐसा कैसे करूंगा (पहली पंक्ति के कर्सर के साथ):

qama:5<CR>y$'a$p:5<CR>dd'ajq3@a

आपको दो बातें जानने की जरूरत है:

  • वह पंक्ति संख्या जिस पर दूसरे समूह की पहली पंक्ति शुरू होती है (मेरे मामले में 5), और
  • प्रत्येक समूह में लाइनों की संख्या (मेरे उदाहरण में 3)।

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

  • qaअगले qमें "बफर" में सब कुछ रिकॉर्ड करता है a
  • ma वर्तमान लाइन पर एक निशान बनाता है।
  • :5<CR> अगले समूह में जाता है।
  • y$ बाकी की रेखा को छोड़ देता है।
  • 'a पहले सेट किए गए चिह्न पर वापस जाता है।
  • $p पंक्ति के अंत में चिपकाया जाता है।
  • :5<CR> दूसरे समूह की पहली पंक्ति में लौटता है।
  • dd इसे हटा देता है।
  • 'a निशान पर लौटता है।
  • jq एक पंक्ति नीचे जाती है, और रिकॉर्डिंग बंद कर देती है।
  • 3@a प्रत्येक पंक्ति के लिए कार्रवाई दोहराता है (मेरे मामले में 3)

1
आपको इसे टाइप करने के [Enter]बाद :5दोनों बार प्रेस करना होगा या यह काम नहीं करेगा।
शॉन जे। गोफ

1
मैं gvim पर हूँ। क्या GVim में उस कमांड को कॉपी और पेस्ट करने का कोई तरीका है? ^ V अपने आप इन्सर्ट मोड में चिपक जाता है (जो समझ में आता है, कि आमतौर पर लोग क्या चाहते हैं) भले ही मैं वर्तमान में सामान्य (?) मोड में हूँ। मैंने कोशिश की, :norm qama:5<CR>y$'a$p:5<CR>dd'ajq3@aलेकिन यह केवल निष्पादित करने के लिए लगता है q
ThiefMaster

1
ThiefMaster: कोशिश करें :let @a="ma:5^My$'a$p:5^Mdd'aj" | normal 4@a, जहाँ ^Mअक्षर CTRL-V को दबाकर टाइप किए गए हैं फिर एंटर करें।
रैंपियन

8

जैसा कि कहीं और उल्लेख किया गया है, ब्लॉक चयन जाने का रास्ता है। लेकिन आप इसके किसी भी प्रकार का उपयोग कर सकते हैं:

:!tail -n -6 % | paste -d '\0' % - | head -n 5

यह विधि UNIX कमांड लाइन पर निर्भर करती है। pasteउपयोगिता लाइन विलय की इस तरह संभाल बनाया गया था।

PASTE(1)                  BSD General Commands Manual                 PASTE(1)

NAME
     paste -- merge corresponding or subsequent lines of files

SYNOPSIS
     paste [-s] [-d list] file ...

DESCRIPTION
     The paste utility concatenates the corresponding lines of the given input files, replacing all but the last file's newline characters with a single tab character,
     and writes the resulting lines to standard output.  If end-of-file is reached on an input file while other input files still contain data, the file is treated as if
     it were an endless source of empty lines.

ब्लॉक चयन का उपयोग केवल जाने का तरीका नहीं है। और न ही यह सबसे सरल है। वांछित (समान paste -d) व्यवहार को लघु विम कमांड के माध्यम से कार्यान्वित किया जा सकता है, जैसा कि मेरे उत्तर में दिखाया गया है ।
ib।

3
इसके अलावा, मैं खिड़कियों पर हूं ताकि समाधान में मेरी लिनक्स मशीन के लिए एसएसएच कनेक्शन शामिल हो और संपादक से टर्मिनल और बैक में चिपकाना।
ThiefMaster

3

नमूना डेटा रैंपियन के समान है।

:1,4s/$/\=getline(line('.')+4)/ | 5,8d

3

मुझे नहीं लगता कि यह बहुत जटिल हो जाएगा। मैं बस virtualedit सेट पर
( :set virtualedit=all)
ब्लॉक 123 और सभी नीचे का चयन करें।
पहले कॉलम के बाद इसे रखें:

abc    123
def    45
...    ...

और 1 अंतरिक्ष के बीच कई जगह हटा दें:

:%s/\s\{2,}/ /g

सवाल वास्तव में कोई रिक्त स्थान के लिए पूछता है, मैं कुछ ऐसा करूँगा gvV:'<,'>s/\s+//g(विम को स्वचालित रूप से '<,'>आपके लिए सम्मिलित करना चाहिए ताकि आपको मैन्युअल रूप से टाइप करने की आवश्यकता न हो)।
बेन

2

मैं जटिल दोहराव का उपयोग करूंगा :)

अगर यह दिया रहे:

aaa
bbb
ccc

AAA
BBB
CCC

पहली पंक्ति पर कर्सर के साथ, निम्नलिखित दबाएं:

qa}jdd''pkJxjq

और फिर आवश्यकतानुसार कई बार दबाएं @a(और आप बाद में उपयोग कर सकते हैं @@)।

आपको समाप्त करना चाहिए:

aaaAAA
bbbBBB
cccCCC

(प्लस ए न्यूलाइन।)

explaination:

  • qa में एक जटिल पुनरावृत्ति दर्ज करना शुरू करता है a

  • } अगली खाली लाइन पर कूदता है

  • jdd अगली पंक्ति हटाता है

  • '' अंतिम छलांग से पहले स्थिति में वापस जाता है

  • p हटाए गए लाइन को वर्तमान के नीचे चिपकाएं

  • kJ पिछले एक के अंत में वर्तमान लाइन को जोड़ें

  • xJसंयुक्त लाइनों के बीच जुड़ने वाले स्थान को हटा दें ; यदि आप स्थान चाहते हैं तो आप इसे छोड़ सकते हैं

  • j अगली पंक्ति पर जाएं

  • q जटिल पुनरावृत्ति रिकॉर्डिंग समाप्त करें

उसके बाद आप @aस्टोर किए गए कॉम्प्लेक्स रिपीट को चलाने के लिए उपयोग करेंगे a, और फिर आप @@अंतिम बार रीप्ले किए गए कॉम्प्लेक्स रिपीट का उपयोग कर सकते हैं ।


1

इसे पूरा करने के कई तरीके हो सकते हैं। मैं निम्नलिखित दो विधियों में से किसी का उपयोग करके पाठ के दो ब्लॉकों को मिला दूंगा।

मान लीजिए कि पहला ब्लॉक लाइन 1 पर है और दूसरा ब्लॉक लाइन 10 से शुरू होता है, लाइन नंबर 1 पर कर्सर की प्रारंभिक स्थिति के साथ।

(\ n का मतलब एंटर की को प्रेस करना है।)

1. abc
   def
   ghi        

10. 123
    456
    789

आदेशों का उपयोग करके मैक्रो के साथ: कॉपी, पेस्ट करें और जुड़ें।

qaqqa: + 9y \ npkJjq2 @ a10G3dd

कमांड का उपयोग करते हुए मैक्रो के साथ nth लाइन नंबर पर एक लाइन चलती है और जुड़ती है।

qcqqc: 10m। \ nkJjq2 @ c

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