वैश्विक खोज और विम में प्रतिस्थापित, कर्सर की स्थिति से शुरू होकर चारों ओर लपेटना


112

जब मैं / सामान्य-मोड कमांड के साथ खोज करता हूं :

/\vSEARCHTERM

विम कर्सर की स्थिति से खोज शुरू करता है और नीचे की ओर जारी रहता है, शीर्ष पर चारों ओर लपेटता है। हालाँकि, जब मैं :substituteकमांड का उपयोग करके खोज और प्रतिस्थापित करता हूं :

:%s/\vBEFORE/AFTER/gc

इसके बजाय फ़ाइल के शीर्ष पर विम शुरू होता है।

क्या विम की खोज करने और कर्सर की स्थिति से शुरू करने और अंतिम छोर तक पहुंचने के बाद चारों ओर लपेटने का एक तरीका है ?


2
\vpattern- 'बहुत जादू' पैटर्न: गैर-अल्फ़ान्यूमेरिक वर्णों की व्याख्या विशेष रेगेक्स प्रतीकों (कोई भागने की ज़रूरत नहीं) के रूप में की जाती है
कार्लोस अराया

वर्तमान स्थिति से शुरू करने और केवल उपयोग करने के बजाय फ़ाइल के चारों ओर लपेटने का क्या मतलब है %? मुझे लगता है कि आप पूरी फ़ाइल के माध्यम से वैसे भी जा रहे हैं के लिए कोई उचित उपयोग नहीं देखते हैं।
15

@tymik उद्देश्य कर्सर से खोज शुरू करना और प्रत्येक परिणाम चरण-दर-चरण जाना था। लेकिन मैंने अब सालों में विम का इस्तेमाल नहीं किया है।
बैस्टेलन

जवाबों:


50

1.  दो-चरणीय प्रतिस्थापन का उपयोग करके व्यवहार को प्राप्त करना कठिन नहीं है:

:,$s/BEFORE/AFTER/gc|1,''-&&

सबसे पहले, प्रतिस्थापन कमांड को चालू लाइन से शुरू होने वाली प्रत्येक पंक्ति के लिए फ़ाइल के अंत तक चलाया जाता है:

,$s/BEFORE/AFTER/gc

फिर, उस :substituteकमांड को :& कमांड (देखें :help :&) का उपयोग करके समान खोज पैटर्न, प्रतिस्थापन स्ट्रिंग और झंडे के साथ दोहराया जाता है :

1,''-&&

उत्तरार्द्ध, हालांकि, फ़ाइल की पहली पंक्ति से लाइनों की सीमा पर प्रतिस्थापन का कार्य करता है जहां पिछले संदर्भ चिह्न को सेट किया गया है, शून्य से एक। चूंकि पहला :substituteकमांड वास्तविक प्रतिस्थापन शुरू करने से पहले कर्सर की स्थिति को संग्रहीत करता है, द्वारा संबोधित  ''लाइन वह लाइन है जो कि प्रतिस्थापन कमांड चलने से पहले वर्तमान एक थी। ( '' पता ' छद्म चिह्न को संदर्भित करता है ; देखें :help :rangeऔर :help ''विवरण के लिए।)

ध्यान दें कि दूसरे कमांड ( | कमांड सेपरेटर के बाद -देखें :help :bar) को पहले एक पैटर्न या झंडे को बदलने पर किसी भी बदलाव की आवश्यकता नहीं है।

2.  कुछ टाइपिंग को बचाने के लिए, कमांड लाइन में उपरोक्त प्रतिस्थापन कमांड के कंकाल को लाने के लिए, एक नॉर्मल-मोड मैपिंग को परिभाषित कर सकता है, जैसे:

:noremap <leader>cs :,$s///gc\|1,''-&&<c-b><right><right><right><right>

<c-b><right><right><right><right>कमांड लाइन की शुरुआत के लिए कर्सर को स्थानांतरित करने के लिए अनुगामी भाग आवश्यक है ( <c-b>) और फिर दाईं ओर ( <right> × 4) चार अक्षर , इस प्रकार इसे पहले दो स्लैश संकेतों के बीच डालकर, उपयोगकर्ता के लिए खोज पैटर्न लिखना शुरू करने के लिए तैयार है। । एक बार वांछित पैटर्न और प्रतिस्थापन तैयार हो जाने के बाद, परिणामी कमांड को दबाकर चलाया जा सकता है Enter

( ऊपर दिए गए मैपिंग में कोई //इसके बजाय विचार कर सकता ///है, यदि कोई पैटर्न टाइप करना पसंद करता है, तो अलग स्लैश वाले टाइप करें, उसके बाद रिप्लेसमेंट स्ट्रिंग, कर्सर को सही तीर का उपयोग करने के बजाय पहले से मौजूद अलग-अलग स्लैश स्टार्टिंग को स्थानांतरित करने के लिए। प्रतिस्थापन भाग।)


1
इस समाधान के साथ एकमात्र मुद्दा यह है कि विकल्प अंतिम (एल) और छोड़ दिया (क्यू) दूसरे स्थानापन्न आदेश को चलने से नहीं रोकते
स्टीव वर्म्यूलेन

@eventualEntropy एक और 'q' प्रेस के लिए संकेत देने के बारे में नीचे दिए गए मेरे समाधान को देखें।
q335r49

2
यदि आप इसे एक मुख्य मानचित्रण में डाल रहे हैं तो पाइप से बचने के लिए (जैसे मैंने किया था) मत भूलना।
जैजैबनी सेप

11
हे भगवान, उन सभी मनमाने चरित्रों का क्या मतलब है। आपने यह कैसे सीखा?
चट्टानी रैकून

2
@ ट्रोपिलियो: तो आप कुछ इस तरह की कोशिश कर सकते हैं :noremap <leader>R :,$s///gc\|1,''-&&<c-b><right><right><right><right>:। यह :,$s///gc|1,''-&&पहले दो स्लैश संकेतों के बीच कर्सर के साथ कमांड लाइन में डालता है । एक बार जब आप वांछित पैटर्न और प्रतिस्थापन टाइप करते हैं, तो आप एंटर दबाकर परिणामी कमांड चला सकते हैं ।
ib।

174

आप पहले से ही एक श्रेणी का उपयोग कर रहे हैं, जिसका अर्थ है संपूर्ण फ़ाइल %का संक्षिप्त हाथ 1,$। वर्तमान लाइन से अंत तक आप का उपयोग करने के लिए .,$। काल का अर्थ है वर्तमान रेखा और $अंतिम पंक्ति का अर्थ है। तो आदेश होगा:

:.,$s/\vBEFORE/AFTER/gc

लेकिन .या वर्तमान रेखा को ग्रहण किया जा सकता है इसलिए हटाया जा सकता है:

:,$s/\vBEFORE/AFTER/gc

अधिक मदद के लिए देखें

:h range

धन्यवाद, मुझे पहले से ही इस बारे में पता था। मैं चाहता हूं कि दस्तावेज़ के अंत तक पहुंचने के बाद खोज और उसके चारों ओर लपेटें। के साथ:।, $ S यह ऐसा नहीं करता है, यह सिर्फ कहता है "पैटर्न नहीं मिला"।
बस्तेलन

7
"अगली दस पंक्तियों" के लिए:10:s/pattern/replace/gc
यहाँ

10
हालांकि यह नहीं है कि ओपी क्या देख रहा था, यह मेरे लिए बहुत उपयोगी था, धन्यवाद!
तोबियों जे

51

%के लिए एक शॉर्टकट है 1,$
(विम मदद => :help :%1 के बराबर, $ (संपूर्ण फ़ाइल)।)

. कर्सर आसन ताकि आप कर सकें

:.,$s/\vBEFORE/AFTER/gc

दस्तावेज़ की शुरुआत से कर्सर तक बदलने के लिए

:1,.s/\vBEFORE/AFTER/gc

आदि

मैं दृढ़ता से सुझाव देता हूं कि आप रेंज के बारे में मैनुअल पढ़ें :help rangeक्योंकि बहुत सारे कमांड एक सीमा के साथ काम करते हैं।


धन्यवाद, मुझे पहले से ही इस बारे में पता था। मैं चाहता हूं कि दस्तावेज़ के अंत तक पहुंचने के बाद खोज और उसके चारों ओर लपेटें। के साथ:।, $ S यह ऐसा नहीं करता है, यह सिर्फ कहता है "पैटर्न नहीं मिला"।
बस्तेलन

@basteln: पोस्ट में टाइपो था // क्या आपने कॉपी और पेस्ट किया था?
सेह

इसलिए आप हर किसी को बदलना चाहते हैं लेकिन जैसा कि आप पुष्टि करना चाहते हैं कि आप वर्तमान स्थिति से शुरू करना चाहते हैं। बस दो बार करें।
mb14

आप n और & का उपयोग कर सकते हैं।
mb14

हम्म, मुझे लगता है कि n और & सबसे अच्छा समाधान है, हालांकि यह बिल्कुल नहीं है कि यह कैसे होना चाहिए (हर मैच पर हां / नहीं संकेत के साथ)। लेकिन निश्चित रूप से काफी अच्छा है, धन्यवाद! :)
बस्तेलन

4

मैं अंतिम रूप से इस तथ्य के समाधान के साथ आया हूं कि खोज छोड़ने से फ़ाइल की शुरुआत के चारों ओर एक विशाल कार्य लिखने के बिना चारों ओर लपेटता है ...

आपको विश्वास नहीं होगा कि मुझे इसके साथ आने में कितना समय लगा। बस एक प्रॉम्प्ट जोड़ें कि क्या रैप करना है: यदि उपयोगकर्ता qफिर से दबाता है , तो रैप न करें। तो मूल रूप से, qqबजाय टैप करके खोज छोड़ दें q! (और यदि आप लपेटना चाहते हैं, तो टाइप करें y)

:,$s/BEFORE/AFTER/gce|echo 'Continue at beginning of file? (y/q)'|if getchar()!=113|1,''-&&|en

मैं वास्तव में एक हॉटकी को मैप किया है। इसलिए, उदाहरण के लिए, यदि आप वर्तमान स्थिति से शुरू होने वाले कर्सर के नीचे हर शब्द को खोजना और बदलना चाहते हैं, तो q*:

exe 'nno q* :,$s/\<<c-r>=expand("<cword>")<cr>\>//gce\|echo "Continue at beginning of file? (y/q)"\|if getchar()==121\|1,''''-&&\|en'.repeat('<left>',77)

मेरी राय में, यह दृष्टिकोण- मेरे जवाब में प्रस्तावित दो आदेशों के बीच अतिरिक्त संकेत सम्मिलित करता है- उपयोगिता में सुधार के बिना अनावश्यक जटिलता। में मूल संस्करण , अगर आप पहले प्रतिस्थापन आदेश (के साथ छोड़ दिया q, lया Esc ) और ऊपर से जारी रखने के लिए नहीं करना चाहते हैं, तो आप पहले से ही दबा सकते हैं qया Esc फिर दूसरा आदेश तुरंत छोड़ने की। यही है, प्रॉम्प्ट का प्रस्तावित जोड़ पहले से मौजूद कार्यक्षमता को प्रभावी ढंग से डुप्लिकेट करने के लिए लगता है।
ib।

यार ... क्या तुमने अपने दृष्टिकोण की कोशिश की है? मान लीजिए कि मैं "लेट" की अगली 3 घटनाओं को "अनलेट" के साथ बदलना चाहता हूं, और फिर - यह कुंजी है - पैराग्राफ को संपादित करना जारी रखें । आपका दृष्टिकोण "प्रेस वाई, वाई, वाई, अब प्रेस क्यू। अब आप पैराग्राफ की पहली पंक्ति पर खोज शुरू करते हैं। फिर से छोड़ने के लिए फिर से दबाएं। अब संपादन करने के लिए जारी रखने के लिए, जहां आप पहले थे, अब वापस जाएं। ओके, जी ;: तो, मूल रूप से: yyyqq ... भ्रमित हो ... g; (या u ^ R) मेरी विधि: yyyqq
q335r49

आदर्श विधि, ज़ाहिर है yyyq, संपादन जारी रखें, जिसमें कोई भटकाव न हो। लेकिन yyyqqलगभग उतना ही अच्छा है, अगर आप उपयोग में आसानी के मामले में एक डबल टैप को एक सिंगल टैप मानते हैं।
q335r49

न तो मूल कमांड और न ही इसके संस्करण को संकेत के साथ कर्सर को उस परिदृश्य में अपनी पूर्व स्थिति में लौटाता है। पूर्व उपयोगकर्ता ऊपर से पैटर्न की पहली घटना पर छोड़ देता है (जहां यह qदूसरी बार दबाने के क्षण में था)। बाद वाला अंतिम घटना पर कर्सर छोड़ देता है जिसे बदल दिया गया था (पहले qदबाए जाने से ठीक पहले )।
ib।

1
में मूल संस्करण है, अगर यह बेहतर है स्वचालित रूप से अपने पूर्व स्थिति के लिए कर्सर वापस जाने के लिए (उपयोगकर्ता बिना लिखे Ctrl + हे ), एक बस जोड़ सकते हैं norm!``आदेश: :,$s/BEFORE/AFTER/gc|1,''-&&|norm!``
ib।

3

यहाँ कुछ बहुत ही कठिन है जो खोज को दो-चरणीय दृष्टिकोण ( :,$s/BEFORE/AFTER/gc|1,''-&&) या एक मध्यवर्ती "फ़ाइल की शुरुआत में जारी रखें" के साथ लपेटने के बारे में चिंताओं को संबोधित करता है ? दृष्टिकोण:

" Define a mapping that calls a command.
nnoremap <Leader>e :Substitute/\v<<C-R>=expand('<cword>')<CR>>//<Left>

" And that command calls a script-local function.
command! -nargs=1 Substitute call s:Substitute(<q-args>)

function! s:Substitute(patterns)
  if getregtype('s') != ''
    let l:register=getreg('s')
  endif
  normal! qs
  redir => l:replacements
  try
    execute ',$s' . a:patterns . 'gce#'
  catch /^Vim:Interrupt$/
    return
  finally
    normal! q
    let l:transcript=getreg('s')
    if exists('l:register')
      call setreg('s', l:register)
    endif
  endtry
  redir END
  if len(l:replacements) > 0
    " At least one instance of pattern was found.
    let l:last=strpart(l:transcript, len(l:transcript) - 1)
    " Note: type the literal <Esc> (^[) here with <C-v><Esc>:
    if l:last ==# 'l' || l:last ==# 'q' || l:last ==# '^['
      " User bailed.
      return
    endif
  endif

  " Loop around to top of file and continue.
  " Avoid unwanted "Backwards range given, OK to swap (y/n)?" messages.
  if line("''") > 1
    1,''-&&"
  endif
endfunction

यह फ़ंक्शन हैक के एक जोड़े का उपयोग करता है यह जांचने के लिए कि क्या हमें शीर्ष पर लपेटना चाहिए:

  • यदि उपयोगकर्ता "l", "q" या "Esc" दबाए तो कोई रैपिंग नहीं, जिनमें से कोई भी गर्भपात करने की इच्छा का संकेत देता है।
  • उस अंतिम कुंजी को "एस" रजिस्टर में मैक्रो रिकॉर्ड करके पता करें और उसके अंतिम चरित्र का निरीक्षण करें।
  • "S" रजिस्टर को सेव / रिस्टोर करके किसी मौजूदा मैक्रो को ओवरराइट करने से बचें।
  • यदि आप कमांड का उपयोग करते समय पहले से ही मैक्रो रिकॉर्ड कर रहे हैं, तो सभी दांव बंद हैं।
  • इंटरप्ट के साथ सही काम करने की कोशिश करता है।
  • अवॉइड "बैकवर्ड रेंज" एक स्पष्ट गार्ड के साथ चेतावनी।

1
मैंने इसे एक छोटे प्लग-इन में निकाला और इसे यहाँ GitHub पर डाला
विजेता

बस अपने प्लगइन स्थापित, यह आकर्षण की तरह काम करता है !! इसे बनाने के लिए आपका बहुत-बहुत धन्यवाद!
16

1

मुझे पार्टी के लिए देर हो रही है, लेकिन मैंने ऐसा नहीं करने के लिए इस तरह के देर से stackoverflow उत्तरदाताओं पर अक्सर भरोसा किया। मैंने रेडिट और स्टैकओवरफ्लो पर संकेत एकत्र किए, और सबसे अच्छा विकल्प \%>...cखोज में पैटर्न का उपयोग करना है , जो आपके कर्सर के बाद ही मेल खाता है।

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

मैंने अपने आप को एक मैपिंग के साथ जोड़ लिया है जो अगली घटना की जगह ले लेता है और उसके बाद कूदता है, और अधिक नहीं (वैसे भी मेरा नाम था)। मुझे यकीन है, इस पर निर्माण, एक वैश्विक प्रतिस्थापन से काम किया जा सकता है। जब एक समाधान की तरह कुछ में लक्ष्य पर काम कर ध्यान रखें :%s/.../.../gकि फिल्टर नीचे पैटर्न में मैचों सभी लेकिन एक प्रतिस्थापन पूर्ण होने के बाद साफ है, इसलिए यह सीधे के बाद उस प्रभाव खो देता है, करने के लिए कूदता है - लाइनों कर्सर की स्थिति के लिए छोड़ दिया अगला मैच और इस तरह एक-एक करके सभी मैचों के माध्यम से चलने में सक्षम है।

fun! g:CleanColFromPattern(prevPattern) return substitute(a:prevPattern, '\V\^\\%>\[0-9]\+c', '', '') endf nmap <F3>n m`:s/\%><C-r>=col(".")-1<CR>c<C-.r>=g:CleanColFromPattern(getreg("/"))<CR>/~/&<CR>:call setreg("/", g:CleanColFromPattern(getreg("/")))<CR>``n


धन्यवाद, मैं सहमत हूं कि एक देर से उत्तर अक्सर सहायक होता है। मैं व्यक्तिगत रूप से लंबे समय से (इस तरह के कारणों के लिए) के बाद से विम का उपयोग नहीं करता हूं, लेकिन मुझे यकीन है कि बहुत से अन्य लोग इसे मददगार पाएंगे।
basteln
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.