Chcę wyszukać i zastąpić każde wystąpienie określonego wzorca liczbą dziesiętną, która zaczyna się 1
i zwiększa o jeden dla każdego dopasowania.
Mogę znaleźć podobnie sformułowane pytania, które okazują się nie dotyczyć zwiększania licznika, ale modyfikowania każdego dopasowania o ustaloną kwotę. Inne podobne pytania dotyczą wstawiania numerów linii zamiast licznika rosnącego.
Przykład przed:
#1
#1.25
#1.5
#2
Po:
#1
#2
#3
#4
Moje prawdziwe dane zawierają o wiele więcej tekstu wokół wszystkich rzeczy, które chcę ponownie numerować.
substitute
hippietrail
źródło
źródło
perldo
, możesz użyć:%perldo s/#\K\d+(\.\d+)?/++$i/ge
Odpowiedzi:
Potrzebujesz podstawienia ze stanem. Pamiętam, że dostarczyłem (/ kilka?) Kompletne rozwiązanie dla tego rodzaju problemów na SO.
Oto inny sposób postępowania (1). Teraz przejdę do 2 kroków:
Co daje:
Jeśli nie jesteś przyzwyczajony do vimowania wyrażeń regularnych, używam
:h /\zs
i\ze
do określenia, który pod-wzór pasuję, a następnie dopasowuję ciąg cyfr, po którym ewentualnie może być kropka i inne cyfry. Nie jest to idealne dla żadnej liczby zmiennoprzecinkowej, ale tutaj wystarczy.Uwaga: Będziesz musiał zawinąć to w kilka funkcji + polecenie dla prostego interfejsu. Znów są przykłady na SO / vim ( tutaj , tutaj , tutaj ) Obecnie znam wystarczająco dużo vima, aby nie obchodzić go zawarcie tej sztuczki w poleceniu. Rzeczywiście będę mógł napisać to polecenie przy pierwszej próbie, podczas gdy zajmie mi kilka minut, aby zapamiętać nazwę polecenia.
(1) Celem jest utrzymanie stanu pomiędzy podstawieniami i zastąpienie bieżącego wystąpienia czymś, co zależy od bieżącego stanu.
Dzięki temu
:s\=
możemy wstawić coś wynikającego z obliczeń.Pozostaje problem państwa. Albo zdefiniujemy funkcję zarządzającą stanem zewnętrznym, albo sami zaktualizujemy stan zewnętrzny. W C (i językach pokrewnych) moglibyśmy użyć czegoś takiego jak
length++
lublength+=1
. Niestety, w skryptach vim+=
nie można używać po wyjęciu z pudełka. Należy go używać z:set
lub z:let
. Oznacza to, że:let length+=1
zwiększa liczbę, ale niczego nie zwraca. Nie możemy pisać:s/pattern/\=(length+=1)
. Potrzebujemy czegoś innego.Potrzebujemy funkcji mutacji. tj. funkcje, które mutują ich dane wejściowe. Mamy
setreg()
,map()
,add()
a prawdopodobnie więcej. Zacznijmy od nich.setreg()
mutuje rejestr. Idealny. Możemy pisaćsetreg('a',@a+1)
jak w rozwiązaniu @Doktor OSwaldo. A jednak to nie wystarczy.setreg()
jest raczej procedurą niż funkcją (dla tych, którzy znają Pascala, Adę ...). Oznacza to, że nic nie zwraca. W rzeczywistości coś zwraca. Nominalne wyjście (tj. Nie wyjątkowe wyjścia) zawsze coś zwraca. Domyślnie, gdy zapomnieliśmy coś zwrócić, zwracane jest 0 - dotyczy to również wbudowanych funkcji. Właśnie dlatego w jego rozwiązaniu wyrażenie zastępcze jest w rzeczywistości\=@a+setreg(...)
. Podstępne, prawda?map()
można również użyć. Jeśli zaczniemy od listy z pojedynczym 0 (:let single_length=[0]
), możemy ją zwiększyć dziękimap(single_length, 'v:val + 1')
. Następnie musimy zwrócić nową długość. W przeciwieństwiesetreg()
,map()
zwraca jego wejście zmutowany. To idealne, długość jest zapisywana na pierwszej (i unikalnej, a więc także na końcu) pozycji na liście. Wyrażeniem zastępującym może być\=map(...)[0]
.add()
to ten, którego często używam z przyzwyczajenia (takmap()
naprawdę myślałem o tym i jeszcze nie porównałem ich odpowiednich występów). Chodzi oadd()
to, aby użyć listy jako bieżącego stanu i dołączyć coś na końcu przed każdą zamianą. Często przechowuję nową wartość na końcu listy i używam jej do zamiany. Jakadd()
również zwraca swoją listę wejściową zmutowany, możemy użyć:\=add(state, Func(state[-1], submatch(0)))[-1]
. W przypadku OP musimy tylko pamiętać, ile wykryto do tej pory dopasowań. Wystarczy zwrócić długość tej listy stanów. Stąd mój\=len(add(state, whatever))
.źródło
\=
że oczekuje wyrażenia, a ponieważ w przeciwieństwie do C,i+=1
nie jest czymś, co zwiększa i zwraca wyrażenie. Oznacza to,\=
że potrzebuję czegoś, co może zmodyfikować licznik i które zwraca wyrażenie (równe temu licznikowi). Jak dotąd jedyne rzeczy, które znalazłem, to funkcje manipulowania listą (i słownikiem). @Doktor OSwaldo użył innej funkcji mutującej (setreg()
). różnica polega na tym, żesetreg()
nigdy nie zwraca niczego, co oznacza, że zawsze zwraca liczbę0
.Ale uwaga, spowoduje to nadpisanie rejestru
a
. Myślę, że jest to trochę bardziej bezpośrednie niż odpowiedź Luca, ale może jego jest szybszy. Jeśli to rozwiązanie jest w jakiś sposób gorsze od jego, chciałbym usłyszeć wszelkie opinie, dlaczego jego odpowiedź jest lepsza. Wszelkie opinie na temat poprawy odpowiedzi będą mile widziane!(Opiera się również na mojej SO odpowiedzi /programming/43539251/how-to-replace-finding-words-with-the-different-in-each-occurrence-in-vi-vim -edi / 43539546 # 43539546 )
źródło
@a+setreg('a',@a+1)
jest krótszy niżlen(add(t,1))
. W przeciwnym razie to fajna inna brudna sztuczka :). Nie myślałem o tym. Jeśli chodzi o użycie funkcji mutacji słownikowej w tekście zastępczym:s
isubstitute()
zauważyłem, że jest to znacznie szybsze niż jawne pętle - stąd implementacja funkcji mojej listy w lh-vim-lib . Myślę, że twoje rozwiązanie będzie na równi z moim, może być trochę szybsze, nie wiem.@a
niezmodyfikowane. W skryptach jest to ważne IMO. Będąc w trybie interaktywnym, jako użytkownik końcowy będę wiedział, którego rejestru mogę użyć. Bałaganowanie rejestru jest mniej ważne. W moim rozwiązaniu w trybie interaktywnym zmienna globalna jest pomieszana z; w skrypcie byłaby to zmienna lokalna.+3
mógłbym napisać coś takiego\=add(thelist, 3 + get(thelist, -1, 0))[-1]
.Znalazłem podobne, ale inne pytanie, które zadałem kilka lat temu i udało mi się zmienić jedną z odpowiedzi, nie w pełni rozumiejąc, co robię i działa świetnie:
W szczególności nie rozumiem, dlaczego moja nie używa
%
lub dlaczego po prostu używam prostej zmiennej, której inne odpowiedzi unikają z jakiegoś powodu.źródło
s//g
instrukcji. W każdym razie jest to interesujące rozwiązanie. Może @LucHermitte może powiedzieć więcej o zaletach i wadach, ponieważ moja wiedza na temat vimscript jest dość ograniczona w porównaniu z jego.printf()
chociaż nie - ponieważ Listy zostały wprowadzone w Vimie 7. Ale muszę przyznać, że nie spodziewałbym się (/ nie pamiętam?), Że<bar>
należy do zakresu:global
- IOW, scenariusz, którego się spodziewałem, polegałby na zastosowaniu:sub
pasujących linii, a następnie zwiększeniui
raz na samym końcu. Spodziewam się, że to rozwiązanie będzie nieco wolniejsze. Ale czy to naprawdę ma znaczenie? Ważne jest, jak łatwo możemy znaleźć działające rozwiązanie z pamięci + próby i błędów. Na przykład Vimgolfers preferuje makra.g/s//
zachowanie lunety pozwala na inne brudne sztuczki. Dziękuję wam więc za interesujące odpowiedzi i dyskusję, często nie uczę się tak wiele z udzielania odpowiedzi =).Na tej stronie są już trzy świetne odpowiedzi , ale, jak sugerował Luc Hermitte w komentarzu , jeśli robisz to od razu , ważne jest to, jak szybko i łatwo można dotrzeć do działającego rozwiązania.
W związku z tym jest to problem, z którego w ogóle nie skorzystałbym
:substitute
: można go łatwo rozwiązać za pomocą zwykłych poleceń trybu normalnego i rekurencyjnego makra:(W razie potrzeby) Najpierw wyłącz
'wrapscan'
. Wyrażenie regularne, którego użyjemy, będzie pasować do pożądanego tekstu wynikowego, a także tekstu początkowego, więc przy'wrapscan'
włączonym makrze w przeciwnym razie odtwarzanie byłoby odtwarzane na zawsze. (Lub dopóki nie zdasz sobie sprawy z tego, co się dzieje i naciśniesz<C-C>
).Ustaw wyszukiwane hasło (używając tego samego podstawowego wyrażenia regularnego, które zostało już wspomniane w istniejących odpowiedziach):
(W razie potrzeby) Wróć do pierwszego meczu, naciskając
N
tyle razy, ile potrzeba,(W razie potrzeby) Zmień pierwsze dopasowanie na żądany tekst:
Wyczyść
"q
rejestr i zacznij rejestrować makro:Wybierz bieżący licznik:
Przejdź do następnego meczu:
Zastąp bieżący licznik tym, który właśnie szarpnęliśmy:
Zwiększ licznik:
Zagraj w makro
q
. Rejestr"q
jest nadal pusty, ponieważ wyczyściliśmy go w kroku 5, więc w tym momencie nic się nie dzieje:Zatrzymaj rejestrowanie makra:
Zagraj w nowe makro i patrz!
Podobnie jak w przypadku wszystkich makr, wygląda to na wiele kroków, gdy wyjaśniono to tak, jak to zrobiłem powyżej, ale zauważ, że ich wpisanie jest dla mnie bardzo szybkie: oprócz płytki rekursywnej do nagrywania makr są one zwykłe polecenia edycyjne Podczas edycji wykonuję cały czas. Jedynym krokiem, w którym musiałem zrobić cokolwiek, nawet zbliżając się do myślenia, był krok 2, w którym napisałem wyrażenie regularne, aby przeprowadzić wyszukiwanie.
Sformatowane jako dwa polecenia trybu wiersza poleceń i seria naciśnięć klawiszy, szybkość tego rodzaju rozwiązania staje się bardziej wyraźna: mogę wyczarować następujące elementy tak szybko, jak potrafię je wpisać 1 :
Prawdopodobnie mógłbym wymyślić inne rozwiązania na tej stronie z odrobiną przemyślenia i odniesieniem do dokumentacji 2 , ale kiedy zrozumiesz, jak działają makra, naprawdę łatwo jest je wyrzucać przy dowolnej prędkości, którą zwykle edytujesz.
1: Tam są sytuacje, w których makra wymagają większej uwagi, ale uważam, że nie pojawią się znacznie w praktyce. Ogólnie rzecz biorąc, sytuacje, w których występują, to takie, w których makro jest jedynym praktycznym rozwiązaniem.
2: Nie sugerując, że inni odpowiadający nie mogliby wymyślić swoich rozwiązań w podobny sposób: po prostu wymagają umiejętności / wiedzy, których osobiście nie mam tak łatwo na wyciągnięcie ręki. Ale wszyscy użytkownicy Vima wiedzą, jak korzystać z regularnych poleceń edycji!
źródło
Wystarczy dodać „#” na końcu plus licznik „c”
Część globalna
g/^#\d\+.*/ let c+=1
pozwala nam zwiększać licznik tylko w liniach, które mają wzórźródło