2010-08-26 9 views
34

की सभी घटनाओं को string_b के साथ बदलने के लिए सबसे आसान तरीका क्या है, जबकि एक ही समय में string_bstring_a में कुछ भी बदल रहा है? मेरी वर्तमान विधि निम्नानुसार है:विम में दो तारों की घटनाओं को स्वैप करने का सबसे आसान तरीका?

:s/string_a/string_c/g 
:s/string_b/string_a/g 
:s/string_c/string_b/g 

हालांकि यह काम करता है, इसके लिए अतिरिक्त टाइपिंग की आवश्यकता होती है और अक्षम लगता है। क्या कोई ऐसा करने के बेहतर तरीके से जानता है?

+2

आप सुपरयूसर.com पर इस प्रश्न को भी आजमा सकते हैं। – janmoesen

+0

यह एक अच्छा सवाल है - कोई यह आसान सोचता है ... मुझे लगता है कि कोई ऐसा फ़ंक्शन लिख सकता है जो दो पैरामीटर स्वीकार करता है और आपके लिए तीन चरणों के माध्यम से जाता है, लेकिन मुझे एक त्वरित वेब खोज के साथ ऐसा फ़ंक्शन ढूंढने की भी उम्मीद है । – Jay

+1

यदि आपकी फ़ाइल में "string_c" पहले से मौजूद है तो यह दृष्टिकोण विफल हो जाएगा। यह ठीक है अगर आप एक इंसान हैं और एक शब्द चुन सकते हैं जो आप जानते हैं कि आपकी फाइल में नहीं है, लेकिन एक अच्छा मध्यस्थ शब्द अनुमान लगाने के लिए एक समारोह को पढ़ना अधिक कठिन होगा। एक पास में ऐसा करने के लिए बेहतर है। –

उत्तर

25

मैं इस तरह यह करना चाहते हैं:

:%s/\v(foo|bar)/\={'foo':'bar','bar':'foo'}[submatch(0)]/g 

लेकिन वह बहुत ज्यादा टाइपिंग है, तो मैं ऐसा करने चाहते हैं:

function! Mirror(dict) 
    for [key, value] in items(a:dict) 
     let a:dict[value] = key 
    endfor 
    return a:dict 
endfunction 

function! S(number) 
    return submatch(a:number) 
endfunction 

:%s/\v(foo|bar)/\=Mirror({'foo':'bar'})[S(0)]/g 

लेकिन वह अभी भी दो बार foo और bar टाइपिंग तो मैं कुछ इस तरह करते हैं चाहते हैं की आवश्यकता है: आप परिसीमक में पारित करने के लिए है

function! SwapWords(dict, ...) 
    let words = keys(a:dict) + values(a:dict) 
    let words = map(words, 'escape(v:val, "|")') 
    if(a:0 == 1) 
     let delimiter = a:1 
    else 
     let delimiter = '/' 
    endif 
    let pattern = '\v(' . join(words, '|') . ')' 
    exe '%s' . delimiter . pattern . delimiter 
     \ . '\=' . string(Mirror(a:dict)) . '[S(0)]' 
     \ . delimiter . 'g' 
endfunction 

:call SwapWords({'foo':'bar'}) 

यदि आपके शब्दों में से एक एक / होता है, आप जो पता अपने शब्दों से कोई भी शामिल है,

:call SwapWords({'foo/bar':'foo/baz'}, '@') 

.eg यह भी एक ही बार में शब्द के कई जोड़े स्वैप करने के लिए सक्षम होने का लाभ है।

:call SwapWords({'foo':'bar', 'baz':'quux'}) 
+0

यह बहुत अच्छा है! मेरा एकमात्र मुद्दा यह है कि यह हर जगह घटनाओं को बदल देता है। क्या लाइनों को पारित करने का कोई तरीका है जिस पर आप स्वैप होना चाहते हैं जैसे कि: 17,34s/foo/bar/g' केवल 17 से 34 लाइनों पर प्रतिस्थापित होगा? – dsg

+1

@dsg SwapWords() में दो परिवर्तन करके किया जा सकता है। पहले पंक्ति पर '... '' के बाद कीवर्ड' रेंज' रखें, फिर 'a: firstline के साथ अंत में ''% s'' को प्रतिस्थापित करें। ','। ए: आखिरी पंक्ति। 'S''। फिर यह एक सीमा ले जाएगा जैसे ': s' करता है। – 00dani

1

आप एक ही आदेश के साथ यह कर सकते हैं, जैसा कि नीचे मेरी कोड में दिखाया गया है:

:%s/\<\(string_a\|string_b\)\>/\=strpart("string_bstring_a", 8 * ("string_b" == submatch(0)), 8)/g 

अद्यतन: stackoverflow में संपादक यहाँ, मुझे पागल गाड़ी चला रहा है क्योंकि इसे हटाने backslahes रहता है ...

8

आप टिम पोप के Abolish प्लगइन के साथ आसानी से कर सकते

:%S/{transmit,receive}/{receive,transmit} 
+0

% एस/{, }/{, }/g जब मैं पूरे शब्दों को स्वैप करने का प्रयास करता हूं, तो यह काम नहीं करता है। मुझे क्या करना चाहिए? –

+1

@JanNetherdrake यदि आप पूरे शब्दों का उपयोग करना चाहते हैं तो Subvert के 'w' ध्वज का उपयोग करें। ':% S/{परीक्षण, foo}/{foo, परीक्षण}/gw'। अधिक जानकारी के लिए ': h abolish-search' देखें। –

2

swapstrings plugin इस के लिए एक उपयोगी आदेश प्रदान करता है: मैं दो शब्द कैसे स्वैप

:SwapStrings string_a string_b 
2

यहाँ है skip & limit

%s/skip/xxxxx/g|%s/limit/skip/g|%s/xxxxx/limit/g

सुंदर यकीन है कि कोई है जो दो तर्क स्वीकार करता है एक छोटा आदेश में बदल सकता है।

संबंधित मुद्दे