Vim wyszukuje i zamienia zaznaczony tekst

109

Powiedzmy, że mamy tekst, wchodzę w tryb wizualny i zaznaczam tekst. Jak szybko wyszukać podświetlony tekst i zastąpić go czymś innym?

Gabriel Solomon
źródło

Odpowiedzi:

135

Spróbuj wykonać następujące czynności lub wstaw do pliku .vimrc

vnoremap <C-r> "hy:%s/<C-r>h//gc<left><left><left>

Naciskając ctrl+ rw trybie wizualnym, zostaniesz poproszony o wprowadzenie tekstu, który ma zostać zastąpiony. Naciśnij, entera następnie potwierdź każdą zmianę, z którą się zgadzasz ylub z którą się odrzucasz n.

To polecenie nadpisuje twój rejestr h, abyś mógł wybrać inny (zmieniając hw powyższym poleceniu na inną małą literę), którego nie używasz.

Mykoła Golubyev
źródło
13
Jeśli pominiesz cin gc, zamiana zostanie wykonana od razu w całym buforze. Jeśli popełniłeś błąd i chcesz go cofnąć, po prostu wpisz uw trybie poleceń. Takie podejście podoba mi się bardziej niż potwierdzanie każdej zamiany (tak się dzieje z cmodyfikatorem).
Niloct
3
vmap * y:let @/ = @"<CR>wybrany jest podświetlony.
kev
8
Jaki jest cel <left><left><left>?
aymericbeaumet
7
@aymericbeaumet, aby umieścić kursor między dwoma ukośnikami, dzięki czemu można łatwo wpisać słowo zastępujące.
mcabrams
5
Zauważ, że jeśli skorzystasz z sugestii @ Niloct o usunięciu cz gc, będziesz musiał również usunąć jedną <left>z końcówek linii.
Nathan Friend
36

To szybkie i proste wyszukiwanie mapowania dla wizualnie podświetlonego tekstu (bez nadpisywania rejestru h) i bez użycia rejestru zależnego od terminala:

" search for visually hightlighted text
vnoremap <c-f> y<ESC>/<c-r>"<CR>   

Jeśli nie podoba ci się ctrl-f, zmień go na swoje preferencje

Po zaznaczeniu tekstu zawsze możesz dokonać szmiany, wpisując po prostu:

%s//<your-replacement-string>

... ponieważ puste wyszukiwanie w spoleceniu wykorzystuje ostatnio wyszukiwany ciąg.

ErichBSchulz
źródło
Kiedy używam tego w mojej konfiguracji vima, control+fzawsze wybiera następny znak, a także to, co wybrałem wizualnie. Jakieś pomysły?
Robert Mark Bram
%s//<your-replacement-string>nie wydaje się działać w przypadku wyróżniania czegoś takiego /tmp/file. staje się po prostu<your-replacement-string>/tmp/file
naisanza
28

To działa również (przynajmniej dla wyborów w jednym wierszu / selekcji, które nie zawierają żadnych znaków specjalnych)

  • zaznacz tekst w trybie wizualnym
  • przeciągnij tekst za pomocą y
  • :s/<C-r>0/

0 to rejestr szarpnięć.

Jak wspominały inne osoby, są na to szybsze sposoby, ale jeśli dopiero zacząłeś uczyć się Vima (tak jak ja), jest to jeden z „ogólnych” sposobów.

// edytuj: Właśnie zdałem sobie sprawę, że podejście `` rejestr '' nie powiedzie się, jeśli /w zaznaczeniu znajdują się znaki takie jak tabulatory, nowe linie lub znaki (musiałbym ręcznie przetworzyć te znaki, aby :spolecenie działało):

wprowadź opis obrazu tutaj

colemik
źródło
2
To jest bardzo proste. O Boże, dlaczego nie ma tego na wiki. No dalej ... Dziękuję za odpowiedź!
Benyamin Limanto
2
To idealna odpowiedź dla tych z nas, którzy wciąż znajdują się na wczesnym etapie krzywej uczenia się Vima. Wiem, że dostosowywanie jest mocną stroną, ale nie chcę kopiować i wklejać złożonego skryptu do mojego vimrc i układanki, aby sprawdzić, jak pasuje do tak prostego problemu, jak ten. Ta odpowiedź nauczyła mnie, że ctrl-R zrzuca rejestr, który będzie przydatny do zapamiętania w innych kontekstach.
nivek
26

Zaakceptowana odpowiedź działa świetnie, chyba że w selekcji wizualnej znajdują się znaki specjalne. Połączyłem ze sobą dwa skrypty ( napisane przez Jeremy'ego Cantrella tutaj i Petera Oddinga ), aby stworzyć polecenie, które pozwoli ci wizualnie wybrać ciąg, który chcesz znaleźć, nawet jeśli zawiera on specjalne znaki wyrażenia regularnego.

" Escape special characters in a string for exact matching.
" This is useful to copying strings from the file to the search tool
" Based on this - http://peterodding.com/code/vim/profile/autoload/xolox/escape.vim
function! EscapeString (string)
  let string=a:string
  " Escape regex characters
  let string = escape(string, '^$.*\/~[]')
  " Escape the line endings
  let string = substitute(string, '\n', '\\n', 'g')
  return string
endfunction

" Get the current visual block for search and replaces
" This function passed the visual block through a string escape function
" Based on this - /programming/676600/vim-replace-selected-text/677918#677918
function! GetVisual() range
  " Save the current register and clipboard
  let reg_save = getreg('"')
  let regtype_save = getregtype('"')
  let cb_save = &clipboard
  set clipboard&

  " Put the current visual selection in the " register
  normal! ""gvy
  let selection = getreg('"')

  " Put the saved registers and clipboards back
  call setreg('"', reg_save, regtype_save)
  let &clipboard = cb_save

  "Escape any special characters in the selection
  let escaped_selection = EscapeString(selection)

  return escaped_selection
endfunction

" Start the find and replace command across the entire file
vmap <leader>z <Esc>:%s/<c-r>=GetVisual()<cr>/

Zawarłem to w moim vimrc, jeśli jest to bardziej przydatne dla kogoś.

bryan kennedy
źródło
2
dzięki za rozwiązanie, łącząc wiele propozycji, skończyło się na tym: vmap <C-r> <Esc>:%s/<c-r>=GetVisual()<cr>//g<left><left>(które po prostu zastępuje wszystkie w pliku)
Peter Butkovic
13

Od Vim 7.4 możesz użyć gnruchu, który wybiera regiony tekstu pasujące do bieżącego wzorca wyszukiwania.

Po użyciu, cgnaby zmienić tekst w aktualnie wybranym dopasowaniu (lub dgnusunąć), w trybie normalnym możesz użyć .do powtórzenia polecenia i wykonania następnego dopasowania.

Jest odcinek Vimcast pokazujący tę funkcję.

Dapeng Li
źródło
3
To świetna odpowiedź!
mauriciojost
To też jest niesamowite. oprócz odpowiedzi colemik. Świetny!
Benyamin Limanto
wow, to jest jak jeden z tych sekretów, które odkrywasz, kiedy głęboko przeglądasz, aby znaleźć dobre rozwiązanie, dzięki!
vdegenne
8

Mykoła Golubyev, Dzięki za cynk! Następujące używa rejestru "+", który (w zależności od terminala) zawiera już podświetlony tekst, oszczędzając przy użyciu rejestru "h".

vnoremap <C-r> <Esc>:%s/<C-r>+//gc<left><left><left>
dmd
źródło
Mój VIM 7.0 na CentOS 5.x nie ma rejestru +. Czy to standardowa funkcja?
dotancohen
3
Zauważam, że uzyskuję dostęp do maszyny CentOS przez Putty i po googlowaniu widzę, że + to rejestr schowka. Wydaje się, że Putty tego nie wspiera! Tak więc ta odpowiedź jest w rzeczywistości zależna od terminala.
dotancohen
Cześć, wypróbowałem twoje polecenie, ale prosi mnie o zastąpienie wystąpienia określonego tekstu w całym pliku, a nie tylko w zaznaczonym tekście
solalito
7

Z http://vim.wikia.com/wiki/Search_and_replace_in_a_visual_selection :

Gdy tekst jest zaznaczony wizualnie, naciśnij:, aby wprowadzić polecenie. Linia poleceń automatycznie wprowadzi zakres:

:'<,'>

Możesz wprowadzić polecenie, takie jak s / red / green / g, aby zamienić każdy czerwony na zielony we wszystkich wierszach ostatniego wizualnego zaznaczenia. Polecenie pojawi się jako:

:'<,'>s/red/green/g

Aby powtórzyć polecenie Ex na poprzednio wybranym bloku, użyj: history. Oznacza to, że naciśnij: następnie, a następnie edytuj poprzednie polecenie.

syvex
źródło
4
tak, to zastępuje czerwony z zielonym w wybranym obszarze - bardzo przydatne, ale nie to, o co prosił operator.
ErichBSchulz
@ErichBSchulz W rzeczywistości robi to na wszystkich wybranych liniach. Tak więc, nawet jeśli wybrana jest tylko część linii, zrobi to na całej linii.
Cully
1
Być może nie odpowiada na pytanie OP, ale to dokładnie odpowiada mojemu wyszukiwaniu "vim szukaj i zamień na wizualną selekcję", gdzie chcę ograniczyć wyszukiwanie i zamienić tylko do wizualnej selekcji, co powoduje to pytanie
icc97
5

Mam to w moim vimrc:

function! GetVisual() range
    let reg_save = getreg('"')
    let regtype_save = getregtype('"')
    let cb_save = &clipboard
    set clipboard&
    normal! ""gvy
    let selection = getreg('"')
    call setreg('"', reg_save, regtype_save)
    let &clipboard = cb_save
    return selection
endfunction

vmap <leader>z :%s/<c-r>=GetVisual()<cr>/

Spowoduje to pobranie wizualnego zaznaczenia i rozpoczęcie z nim polecenia zastępowania.

EDYCJA: Powinienem zaznaczyć, że to nie działa z wielowierszowymi selekcjami wizualnymi. Chociaż GetVisual () nie ma problemu z jego zwróceniem, nie jestem pewien, jak poprawnie umieścić go w wierszu poleceń. Jeśli ktoś ma jakieś wskazówki, jak mogę to zrobić, proszę o komentarz.

Jeremy Cantrell
źródło
2

Nie sądzę, że możesz to zrobić po wyjęciu z pudełka. Ale wiele osób lubi tę funkcję, więc jest mnóstwo makr i tym podobnych (dodałem to sam). Oto przykład, który możesz dodać; wystarczy nacisnąć, *aby wyszukać następne dopasowanie w wizualnie wybranym tekście.

John Feminella
źródło
2

Inne odpowiedzi są dobre, ale nie unikają znaków specjalnych. Odpowiedź od @brian Kennedy przedstawia sposób na ucieczkę, ale to wymaga dużo kodu. Na przykład w przypadku adresu URL, ucieczka jest obowiązkowa lub wyszukiwanie zatrzyma się na „:”.

Jak napisano na vim.fandom.com/wiki/Search_for_visually_selected_text , możesz zrobić oneliner, aby wyszukać i uciec od niektórych znaków. Możesz uciec przed postaciami, które chcesz, ja wybrałem ucieczkę /\: :

vnoremap // y/\V<C-R>=escape(@",'/\:')<CR><CR>

Na tej mapie muszę nacisnąć //w trybie wizualnym, aby przeszukać aktualnie wybrany tekst w całym buforze.

RomainTT
źródło
1

Moja ulubiona krótka wersja to

vnoremap s / y: s / "/

Następnie możesz zaznaczyć wybór i po prostu nacisnąć s /, aby rozpocząć dla niego polecenie zamiany.

Alex
źródło
U mnie nie zadziałało, potraktowano "jako dosłowne. <c-r>"działał jednak
Josh Bodah
1

Nie mam przedstawiciela do komentowania, więc dodaję kolejną odpowiedź ...

vnoremap <C-r> "0y<Esc>:%s/<C-r>0//g<left><left>

@dmd i @dotancohen: działało to dla mnie bez zużywania "h(jawnie używa 0, które i tak jest ostatnią pozycją szarpnięcia) i działa z kitem ssh -> mint (lmde); nie wiem o centach. Używa również komentarzy @Niloct i @Nathan Friend, aby usunąć potwierdzenie.

10'004
źródło
1

Przykład 1. Cytuj zaznaczenie gwiazdkami, trzymaj kursor na początku wyboru.

:%s,\%#\%V\_.*\%V/,**&**,c 

Przykład 2. Potokuj zaznaczony tekst za pomocą base64:

:%s!\%#\%V\_.*\%V!\=system("base64 -w 0",@")!c

Wyjaśnienie LHS:

\%# matches cursor 
\%V matches inside the selection only
\_. matches any character.
\_.* matches beginning to end of selection.

Wyjaśnienie RHS:

\=expr()  Replace match with result of expr() for each substitution.
mosh
źródło
0

Miałem nadzieję, że w Vimie pojawił się sposób na zastąpienie słowa, bez konieczności ponownego wpisywania go w pierwszej kolejności. Jest, chociaż będzie działać tylko dla tekstu do znaku granicy słowa.

Po najechaniu kursorem na słowo naciśnij *lub, #aby podświetlić słowo i przeskocz do następnej / poprzedniej lokalizacji (jeśli nie chcesz zmieniać lokalizacji w pliku, naciśnij przeciwny klawisz, aby wrócić do lokalizacji byłeś właśnie na).

Następnie wpisz:

%s//<your-replacement-string>

Jak wspomniano w odpowiedzi innej osoby, jeśli %sotrzyma pusty wpis między ukośnikami, to używa wcześniej wyszukiwanego słowa. Naciskając *lub #, szukasz słowa pod kursorem, co powoduje, że jest to ostatnio wyszukiwane słowo.

W końcu wystarczy sześć lub siedem naciśnięć klawiszy + długość słowa zastępczego, aby to wykonać i nie wymaga makra ani edycji pliku .vimrc.

Cameron Gagnon
źródło