Jak dodać stałe numery linii do pliku?

22

Mam taki plik tekstowy (używając gVim w systemie Windows)

foo bar baz quux 
corge grault garply 
waldo fred plugh 
[...150 more lines...]
xyzzy thud

Chcę dodać numer do każdej linii w pliku. Nie używa :set number, ale dodaje numer jako tekst przed każdym wierszem, jak pokazano poniżej, więc numer jest częścią pliku.

1. foo bar baz quux 
2. corge grault garply 
3. waldo fred plugh 
[...~150 more lines...]
155. xyzzy thud
roblogic
źródło
awkjest prawdopodobnie narzędziem do tego zadania. Ale jestem na Windowsie (westchnienie).
roblogic
Odpowiedziałem już tutaj , nieważne :)
roblogic
1
Być może ... Czy to jest bardziej ogólne?
muru
Jest podobnie, ale nie wiedziałbym, jakie są stałe numery linii. Po drugie, drugie pytanie dotyczy wszystkich wierszy (i odpowiedź na to pytanie) dla gVim w systemie Windows, a jest to prosta numerowana lista dla jednego akapitu tylko w zwykłym vimie.
kenorb
3
Cóż, myślę, że post używa „permanent”, co oznacza, że ​​bufor ma zostać zmodyfikowany i że liczby nie są czymś czysto wizualnym (tak jak ty). Powodem określenia gvima w systemie Windows jest unikanie zewnętrznych narzędzi, takich jak catlub nl, które mogą wykonywać linie liczbowe, ale nie są ogólnie dostępne w systemie Windows (jak wskazuje OP z ich komentarza awk). Dwa pierwsze rozwiązania to czysty Vim. Wreszcie, wszystkie linie w stosunku do jednego para to tylko kwestia wyboru zakresu. Oczywiście nie jest to duży problem.
muru

Odpowiedzi:

37

W czystym stylu Vima:

:%s/^/\=line('.').". "

Wyjaśnienie:

:%s/^/            " the substitution will be applied to the beginning of every line
\=                " the rest of the replacement part is an expression
line('.').". "    " the expression returns the current line number concatenated with a dot and a space

Zobacz :help \=i :help line().

Użycie wyrażenia w części zamiennej jest bardzo potężne, a FWIW całkiem niezły punkt wejścia do vimscript.

romainl
źródło
Jak mogę dodać to bardzo przydatne polecenie do mapy klawiszy w vimrc?
cosmicraga
Aby przejść do tematu pomocy vima na temat podstawienia::help sub-replace-expression
akurtser
9

Jedną fajną rzeczą w makrach Vima jest to, że mogą się powtarzać (mogą się wywoływać):

  1. Wyczyść rejestr q: qqq
  2. Dodaj numer do pierwszego wiersza: ggI1.(nie zapomnij o spacji!)
  3. Wróć do początku linii i rozpocznij rejestrowanie makra: 0qq
  4. Skopiuj numer: yW
  5. Przejdź w dół linii i wklej liczbę: +P
  6. Wróć na początek linii i zwiększ liczbę: 0<c-a>
  7. Wróć do początku linii (aby makro nie pękało, gdy dochodzi do podwójnych cyfr!): 0
  8. Wywołaj makro raz, aby było rekurencyjne. W tym momencie nie ma jeszcze nic w rejestrze q, więc nic się nie stanie: @q.
  9. Zapisz makro: q
  10. Wywołaj makro jeszcze raz i patrz, jak lecą iskry !: @@

Makro będzie dalej wywoływać się, dopóki nie osiągnie końca pliku.

Możesz użyć sztuczki makro rekurencyjnej do wielu innych podobnych problemów, więc warto o tym pamiętać.

Jeśli z jakiegoś powodu nie chcesz używać makra rekurencyjnego, możesz pominąć kroki 1 i 8 i użyć licznika, aby uruchomić makro wiele razy, np. 100@qUruchomi makro q100 razy.

Bogaty
źródło
1
Potężne rzeczy, kłaniam się waszemu opanowaniu. Makra są dla mnie jak czarna magia ...
roblogic
1
@ropata, makro jest tylko sekwencją (głównie) poleceń trybu normalnego.
romainl
1
@romainl Myślę, że lepiej myśleć o tym jako o sekwencji klawiszy .
Bogaty
2
@Rich, może to być sekwencja wielu rzeczy, w tym poleceń ex.
romainl
2
@romainl Tak, dlatego myślę, że najlepiej myśleć o tym jak o naciśnięciu klawisza. Odtwarza dokładnie to, co piszesz na klawiaturze (w tym, jak mówisz, polecenia ex), tak jakbyś wpisał wszystko ręcznie.
Bogaty
7

Lubię używać globalnego polecenia vim do wykonywania takich zadań. Dotyczy to dodawania iteracji na początku linii lub modyfikowania symbolu w tekście. Wygląda na bardziej skomplikowane niż inne rozwiązania, ale jest dość elastycznym wzorem do użycia, gdy masz go pod ręką, i można go łatwo modyfikować bez zastanowienia.

Najpierw wybierz zakres (które linie chcesz zastosować). Zwykle używam znaków (np. maW pierwszym wierszu i mbw drugim, ale możesz także użyć numerów linii lub wyboru wizualnego), a następnie wprowadź modyfikację następującego polecenia (obecnie dostosowanego do twojego przypadku użycia)

:let i=1|'a,'bg/^/s/^/\=i.". "/|let i=i+1

Dekonstrukcja

:let i=1

To ustawia zmienną iz wartością początkową. Zwykle listy zaczynają się od 1, więc ustawiam i na 1.

|

Pasek rozpoczyna nowe polecenie

'a,'b

Ustawia zakres następnego polecenia. Przechodzę od znaku ado znaku b, który zostałby ustawiony w pierwszym wierszu i ostatnim wierszu listy.

g/^/

To jest polecenie globalne. Przeszukuje plik (lub zakres) pod kątem określonego wyrażenia regularnego i wykona resztę wiersza poleceń na każdym z pasujących wierszy. Dopasowuję każdą linię, szukając „początku linii”. Jeśli masz tekst podobny do

Item some txt
other text

Item second item
whatever
Item third

i chcę tylko umieścić te etykiety przed Itemi zignorować inne wiersze, zrób g/Item/lub g/^Item/zamiast (zakładając dosłowny tekst pozycji)

s/^/\=i.". "/

Spowoduje to wykonanie wyrażenia regularnego w celu zastąpienia początku wiersza wartością ikonkatenowaną przez a .. Zasadniczo możesz to zrobić w dowolny sposób (na przykład zastąp etykietę Itemnumerem).

|let i=i+1

Mimo że pasek rozpoczyna nowe polecenie, ustawia drugie polecenie do uruchomienia w ramach polecenia globalnego, zamiast po zakończeniu globalnego. W rezultacie zwiększamy, izanim kolejny wiersz zostanie przetworzony przez g. Oto inne miejsce elastyczności. Modyfikacja i może być dowolna (inkrementacja o 2, wywołanie funkcji, która generuje następny element sekwencji Fibonacciego, cokolwiek).

John O'M.
źródło
7

Dodaj liczby do wszystkich linii

Można użyć poleceń :%!nl -balub :%!cat -npoleceń, które dodadzą numery linii do wszystkich linii.

W systemie Windows musisz mieć zainstalowany Cygwin / MSYS / SUA.

Dodaj liczby do wybranych linii

Aby dodać liczby tylko do wybranych linii, wybierz je w trybie wizualnym ( vi kursorach), a następnie po zakończeniu - wykonaj polecenie: :%!nl(zignoruj ​​puste linie) lub :%!cat -n(w tym puste linie).

Formatowanie

Aby usunąć dodatkowe spacje, zaznacz je w bloku wizualnym ( Ctrl+ v) i usuń je ( x).

Aby dodać kilka znaków ( ., :, )) po numerach, wybierz je w polu widzenia ( Ctrl+ v), a następnie dołączyć znak ( Awpisz znak, a następnie zakończyć Esc).

kenorb
źródło
2
To nie zapewnia takiego samego formatowania jak podane w pytaniu. Lubię jednak prostotę rozwiązania.
Karl Yngve Lervåg
@ KarlYngveLervåg Dzięki, zawarłem to w odpowiedzi.
kenorb
5

Modyfikacja odpowiedzi Romainla :

:%s/^\(\d\+\. \)\?/\=line('.').". "

To nie tylko doda numery linii, ale także zastąpi numery linii wychodzących, które już tam są. Jeśli wstawisz linię w połowie drogi, wszystko zmieni numerację zgodnie z oczekiwaniami.

Działa to poprzez zastąpienie dowolnej liczby, po której następuje. i spację na początku linii z nowym numerem. To oczywiście pęknie, jeśli masz linię, która już zaczyna się od tego wzoru, więc używaj z przemyśleniem.

Dodana część:

  • ^ - Początek linii
  • \( - Uruchom nową podgrupę
  • \d\+ - Dopasuj cyfrę raz lub więcej razy
  • \. - Dopasuj kropkę ( .) i spację .
  • \) - Koniec podgrupy
  • \? - Ustaw grupę jako opcjonalną, aby działała jak poprzednio, jeśli w tej linii nie ma jeszcze numeru.

Dodatkowa wskazówka:
Aby usunąć numery linii, możesz użyć tego samego wzoru z pustą częścią repalce:

:%s/^\(\d\+\. \)\?//
Martin Tournoij
źródło
5
I1. <esc>^qqyWjP^<C-a>q

To numeruje pierwsze dwa wiersze i możesz nacisnąć, @qaby ponumerować kolejne wiersze (lub wpisz np., 18@qJeśli chcesz numerować łącznie 20 wierszy).

Wyjaśnienie:

I1. <esc>  Number the first line
hqq        Go back to the start of the line and start recording a macro
yWjP       Copy the line number to the next line
^<C-a>     Increment the next line's line number
q          Finish recording

Zaletą tego jest to, że nie wymaga żadnych zewnętrznych poleceń, co jest przydatne, jeśli na przykład pracujesz z Vimem w systemie Windows.

Klamka
źródło
Po wpisaniu 1. <esc>hznajdujesz się w drugiej kolumnie, a nie w pierwszej kolumnie. Chciałbym wymienić hsię 0, po czym myślę, że rozwiązanie powinno być bardzo dobre.
Karl Yngve Lervåg
@ KarlYngveLervåg Ups, to była literówka. Dzięki, naprawiłem to.
Klamka
Nie ma problemu. Jednak nadal nie zaktualizowałeś tego wyjaśnienia. Ponadto: na wielu klawiaturach ^czeka na drugi znak, aby umożliwić takie kombinacje pisania ^a -> â. Nadal zgadzam się, że jest to najlepsze rozwiązanie, ale myślę, że należy o tym wspomnieć.
Karl Yngve Lervåg
3

Myślę, że wybrana odpowiedź jest najlepsza, ale w różnorodności zaoferuję alternatywę za pomocą zewnętrznego programu:

:%!cat -n

Spowoduje to przefiltrowanie całego bufora (zgodnie z oznaczeniem %) przez zewnętrzny program, catw którym -nflaga poprzedza każdą linię wejścia numerem linii.

To oczywiście wymaga catzainstalowania, co dotyczy (prawdopodobnie) wszystkich systemów uniksowych.

Sprawdź :help :range!więcej szczegółów na temat filtrowania przez programy zewnętrzne.

tommcdo
źródło
1
Zdaję sobie sprawę, że pytający używa gVima w systemie Windows, więc to rozwiązanie prawdopodobnie tam nie zadziała. Myślę jednak, że nadal daje to niektórym możliwość uczenia się z tego.
tommcdo
Jeśli zainstalowałeś msysgiti dodałeś to do ŚCIEŻKI (IIRC to opcja instalacji), to rozwiązanie powinno również działać w systemie Windows.
Martin Tournoij
4
cat -nnie jest POSIX, ale nljest, więc może być lepszą opcją.
muru
2

Trochę zhackowane rozwiązanie może wyglądać następująco (wszystko, co napisano między <a>, należy wstawić po naciśnięciu Ctrl+ v):

:%normal :redir @"<Enter>:-=<Enter>:redir END<Enter>I<C-R>".<Tab><Esc>kdd

Dekonstrukcja

:%normal {commands}

uruchamia polecenie trybu normalnego w każdej linii określonej przez zakres, w tym przypadku w każdej linii

:redir @"

przekierowuje każde wyjście wykonane przez polecenia ex do nienazwanego bufora.

:.=

to polecenie ex, które wyświetla bieżący numer linii (niestety z poprzednią nową linią)

:redir END

przestaje przekierowywać do nienazwanego bufora

I<C-R>".<Tab><Esc>

wstawia zawartość nienazwanego bufora za pomocą. oraz tabulator na początku każdej linii i wychodzi z trybu wstawiania.

kdd

idzie jeden wiersz w górę i usuwa nowy wiersz, który jest wynikiem polecenia:. =.

FloriOn
źródło