Как добавить постоянные номера строк в файл?

22

У меня есть текстовый файл, как это (с помощью gVim на Windows)

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

Я хочу добавить номер к каждой строке в файле. Не используется :set number, но добавляет число в виде текста, предшествующего каждой строке, следующим образом, чтобы число было частью файла.

1. foo bar baz quux 
2. corge grault garply 
3. waldo fred plugh 
[...~150 more lines...]
155. xyzzy thud
roblogic
источник
awkвероятно инструмент для этой работы. Но я на Windows (вздох).
roblogic
Ответили уже здесь , неважно :)
roblogic
1
Возможно .. Или это более общее?
Муру
Это похоже, но я не знаю, что такое постоянные номера строк. Во-вторых, другой вопрос касается всех строк (и ответ делает это) специально для Windows на gVim, и это простой нумерованный список для одного абзаца только в простом vim.
Кенорб
3
Ну, я предполагаю, что пост использует "постоянный", не означает, что буфер должен быть изменен, и что числа не являются чем-то чисто визуальным (таким же, как вы). Причина указания gvim в Windows состоит в том, чтобы избегать внешних утилит, таких как catили nl, которые могут делать числовые строки, но обычно не доступны в Windows (как указывает OP из их комментариев awk). Лучшие два решения - чистый Vim. И наконец, все строки против одного пункта - просто вопрос выбора диапазона. Очевидно, не большая проблема.
Муру

Ответы:

37

В чистом виде Vim:

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

Объяснение:

:%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

Смотрите :help \=и :help line().

Использование выражения в заменяющей части очень эффективно, и FWIW является хорошей отправной точкой для входа в vimscript.

romainl
источник
Как я могу добавить эту очень полезную команду в раскладку ключей в vimrc?
Космикрага
Чтобы попасть в раздел справки vim для замены::help sub-replace-expression
akurtser
9

Хорошая особенность макросов Vim заключается в том, что они могут возвращаться (они могут вызывать себя):

  1. Очистить регистр q: qqq
  2. Добавьте номер в первую строку: ggI1.(не забывайте пробел!)
  3. Вернитесь к началу строки и начните запись макроса: 0qq
  4. Скопируйте номер: yW
  5. Двигайтесь вниз по строке и вставьте число: +P
  6. Вернитесь к началу строки и увеличьте число: 0<c-a>
  7. Вернитесь к началу строки (чтобы макрос не разрывался, когда он удваивается!): 0
  8. Вызовите макрос один раз, чтобы сделать его рекурсивным. На данный момент, до сих пор ничего в регистре д, так что ничего не произойдет: @q.
  9. Сохранить макрос: q
  10. Вызовите макрос еще раз, и посмотрите, как летят искры! @@

Макрос продолжит вызывать себя, пока не достигнет конца файла.

Вы можете использовать рекурсивный макро-трюк для множества других подобных проблем, так что об этом стоит знать.

Если по какой-то причине вы не хотите использовать рекурсивный макрос, вы можете пропустить шаги 1 и 8 и использовать счетчик для запуска макроса несколько раз, например 100@q, запуск макроса q100 раз.

Богатый
источник
1
Мощные вещи, я преклоняюсь перед вашим мастерством. Макросы для меня как черная магия ...
roblogic
1
@ropata, макрос - это только последовательность (в основном) команд обычного режима.
romainl
1
@romainl Я думаю, что лучше думать об этом как о последовательности нажатий клавиш .
Богатый
2
@Rich, это может быть последовательность многих вещей, включая команды ex.
romainl
2
@romainl Да, именно поэтому я думаю, что лучше думать об этом как о нажатиях клавиш. Он воспроизводит именно то, что вы печатаете на клавиатуре (включая, как вы говорите, команды ex), как если бы вы набрали все это вручную.
Богатый
7

Мне нравится использовать команду vim global для выполнения подобных задач. Это относится к добавлению итерации в начало строки или изменению символа в тексте. Он выглядит сложнее, чем другие решения, но это довольно гибкий шаблон, который можно использовать, когда он вам удобен, и его легко изменить, не задумываясь.

Во-первых, выберите свой диапазон (какие линии вы хотите применить это). Я обычно использую метки (например, maв первой строке и mbво второй, но вы также можете использовать номера строк или визуальный выбор), затем введите модификацию следующей команды (в настоящее время настроена для вашего варианта использования)

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

Деконструкция

:let i=1

Это устанавливает переменную iс начальным значением. Обычно списки начинаются с 1, поэтому я устанавливаю i в 1.

|

Бар запускает новую команду

'a,'b

Это устанавливает диапазон следующей команды. Я иду от отметки aк отметке b, которая будет установлена ​​в первой и последней строке вашего списка.

g/^/

Это глобальная команда. Он ищет в файле (или диапазоне) заданное регулярное выражение и выполняет оставшуюся часть командной строки в каждой строке, которая соответствует. Я сопоставляю каждую строку в поиске «начало строки». Если у вас был текст, как

Item some txt
other text

Item second item
whatever
Item third

и только хотите поставить эти метки перед Itemи игнорировать другие строки, сделать g/Item/или g/^Item/вместо этого (при условии буквального текста элемента)

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

Это выполняет регулярное выражение для замены начала строки значением iсцепленного с .. Как правило, вы можете сделать это с чем угодно (например, заменить метку Itemс номером).

|let i=i+1

Даже если панель запускает новую команду, она устанавливает вторую команду для запуска в глобальной команде, а не после завершения глобальной. В результате мы увеличиваем значение iперед обработкой следующей строки g. Вот еще одно место гибкости. Модификация i может быть чем угодно (увеличить на 2, вызвать функцию, которая генерирует следующий элемент последовательности Фибоначчи, что угодно).

Джон О'М.
источник
7

Добавить номера ко всем строкам

Можно использовать команды :%!nl -baили, :%!cat -nкоторые будут добавлять номера строк ко всем строкам.

В Windows у вас должен быть установлен Cygwin / MSYS / SUA.

Добавить номера в выбранные строки

Чтобы добавить числа только для выбранных строк, выберите их в визуальном режиме ( vи курсоры), затем, когда закончите, выполните команду: :%!nl(игнорируйте пустые строки) или :%!cat -n(включая пустые строки).

Форматирование

Чтобы удалить лишние пробелы, выделите их в визуальном блоке ( Ctrl+ v) и удалите их ( x).

Для того, чтобы добавить некоторые символы ( ., :, )) после цифр, выберите их в визуальном блоке ( Ctrl+ v), затем добавить символ ( Aвведите символ, а затем закончить с Esc).

kenorb
источник
2
Это не дает такое же форматирование, как указано в вопросе. Однако мне нравится простота решения.
Карл Ингве Лервог
@ KarlYngveLervåg Спасибо, что включены в ответ.
Кенорб
5

Модификация ответа Роменля :

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

Это не только добавит номера строк, но и заменит существующие номера строк, если они уже есть. Если вы вставили строку посередине, она перенумерует все, как ожидалось.

Это работает, заменяя любое число с последующим. и пробел в начале строки с новым номером. Это, очевидно, сломается, если у вас есть строка, которая уже начинается с этого шаблона, так что используйте с мыслью.

Добавленная часть:

  • ^ - начало строки
  • \( - Начать новую подгруппу
  • \d\+ - Совпадение цифры один или несколько раз
  • \. - Совпадение точки ( .) и пробела .
  • \) - Конец подгруппы
  • \? - Сделайте группу необязательной, чтобы она работала как прежде, если в этой строке еще нет номера.

Дополнительная подсказка:
чтобы удалить номера строк, вы можете использовать тот же шаблон с пустой частью ответа:

:%s/^\(\d\+\. \)\?//
Мартин Турной
источник
5
I1. <esc>^qqyWjP^<C-a>q

Это нумерация первых двух строк, и вы можете нажать @qдля нумерации последующих строк (или набрать, например, 18@qесли вы хотите, чтобы всего было 20 строк).

Объяснение:

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

Преимущество этого в том, что он не требует никаких внешних команд, что полезно, например, если вы работаете с Vim в Windows.

Дверная ручка
источник
После ввода 1. <esc>hвы находитесь во втором столбце, а не в первом столбце. Я хотел бы заменить hс 0, после чего я думаю , что ваше решение должно быть очень хорошим.
Карл Ингве Лервог
@ KarlYngveLervåg Ой, это была опечатка. Спасибо, исправили это.
дверная ручка
Нет проблем. Тем не менее, вы все еще не обновили объяснение. Также: на многих клавиатурах ^ждет второго символа, чтобы разрешить вводить комбинации вроде ^a -> â. Я все еще согласен с тем, что это лучшее решение, но я думаю, что об этом следует упомянуть.
Карл Ингве Лервог,
3

Я думаю, что выбранный ответ является лучшим, но, несмотря на разнообразие, я предложу альтернативу, используя внешнюю программу:

:%!cat -n

Это отфильтрует весь ваш буфер (как обозначено %) через внешнюю программу cat, где -nфлаг добавляет каждую строку ввода к номеру строки.

Это, конечно, требует, чтобы вы catустановили, что верно (вероятно) для всех Unix-подобных систем.

Проверьте :help :range!для более подробной информации о фильтрации через внешние программы.

tommcdo
источник
1
Я понимаю, что спрашивающий использует gVim в Windows, так что это решение, вероятно, не будет работать там. Тем не менее, я думаю, что это все еще дает некоторую возможность другим извлечь уроки из этого.
Tommcdo
Если вы установили msysgitи добавили это в PATH (IIRC - это вариант установки), это решение также должно работать в Windows.
Мартин Турной
4
cat -nне POSIX, но nlесть, так что это может быть лучшим вариантом.
Муру
2

Немного хакерское решение может быть следующим (все, что написано между <и>, должно быть вставлено после нажатия Ctrl+ v):

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

Деконструкция

:%normal {commands}

запускает команду нормального режима в каждой строке, указанной диапазоном, в данном случае в каждой строке

:redir @"

перенаправляет каждый вывод, сделанный командами ex, в безымянный буфер.

:.=

это команда ex, которая выводит текущий номер строки (к сожалению, с предыдущей строкой)

:redir END

перестает перенаправлять в безымянный буфер

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

вставляет содержимое безымянного буфера с. и вкладка в начало каждой строки и выход из режима вставки.

kdd

идет на одну строку вверх и удаляет символ новой строки, который является результатом команды:. =.

FloriOn
источник