Vim: s заменяет первые N <g вхождений в строке


13

В vim я иногда имею возможность заменить первые несколько совпадений в строке, но не каждый, как gхотелось бы. например:

a a a a a

в

b b b a a

Я знаю, что мог бы использовать :s/a/b/[enter]:[up][enter]:[up][enter], но это достаточно утомительно в трех повторениях, у меня есть строки с потенциально более 10 заменами.
Я пытался:

  • :s/a/b/3g: vim жаловался на висячих персонажей.
  • :s/a/b/3: изменяет первое вхождение в этой и следующих двух строках.
  • 3:s/a/b: такой же, как предыдущий.
  • :s/a/b/g3: изменяет все вхождения в этой и следующих двух строках.
  • :3s/a/b: изменяет первое вхождение в строке 3.
  • :/a/,3/a/s/a/b: изменяет первое вхождение в каждой строке между следующей aи третьей строкой, содержащейся aв файле (при необходимости запрашивая отмену).
  • :/a/,/\([^a]*a\)\{3\}/s/a/b/: изменяет первое вхождение в каждой строке между этим и следующим с 3 aс на нем (и это было бы нелегко расширить с помощью многосимвольного поиска).

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

Кто-нибудь знает, как это сделать?

(бонусные баллы за определенный диапазон, например, со второго по четвертое)


2
Я почти уверен, что вы не можете сделать это в vim, но чтобы сделать его менее утомительным, знаете ли вы о «n» и «». в визуальном режиме? То есть вы используете / pattern /, чтобы найти объект, который нужно изменить, измените его, используя «cw» или что-то еще, затем используйте «n» (просто n, без кавычек), чтобы найти следующий шаблон, и нажмите «.» (просто точка, без кавычек), чтобы выполнить последнее редактирование.
Брюс Эдигер

@BruceEdiger, о котором я знал, nи .хотя я не думал использовать их здесь. Конечно, улучшение, спасибо.
Кевин

s/a/=something/должен сделать трюк ( :help sub-replace-=). Я не достаточно свободно говорю на Vim, чтобы сразу писать something.
Жиль "ТАК - перестань быть злым"

Примечание: :[up][enter]можно заменить на &, который все еще не идеален, но по крайней мере менее болезнен.
Kowh

Ответы:


10

Основываясь на :s/pattern/replacement/gc идее Samus_ (которая кажется наиболее простым способом обеспечения правильной работы, когда шаблон содержится в строке замены), заменить вхождения со 2-го по 4-е в одной строке:

:call feedkeys("nyyyq") | s/pat/string/gc

feedkeys()это функция, которая вставляет строку ввода в очередь ввода с клавиатуры. Смысл в том, чтобы сделать предварительный подсчет, чтобы вам не пришлось беспокоиться о потере счета или прерывании.

Для более общем случае, чтобы заменить МТЙ через N - й вхождения в одной строке для N больше или равно к очень большим М :

:call feedkeys(repeat("n", M-1) . repeat("y", N-M+1) . "q") | s/pat/string/gc

Замените M и N значениями, которые вы хотите (вы даже можете позволить vimсделать тривиальную ментальную арифметику, если вы не хотите делать это самостоятельно). Обратите внимание, что .это оператор конкатенации строк VimL. Очевидно , что это только сохраняет нажатия клавиш для больших M . Если вы часто используете эту функцию, это может сэкономить ваше время, чтобы поместить вышеперечисленное в пользовательскую команду или функцию какого-либо рода, так как ее совсем немного набрать.


Хм. Мне нравится этот. Я должен быть в состоянии написать функцию для этого тоже.
Кевин

8

Для первого вопроса я бы сделал:

:s/a/b
&&

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

:s/a/b/gc

Затем вы отвечаете «нет» первым n совпадениям и «да» остальным.


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

6
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a

:3,6g/^/let i=0 | while i<3 | s/a/b/ | let i+=1 | endwhile

a a a a a
a a a a a
b b b a a
b b b a a
b b b a a
b b b a a
a a a a a

1
Это хорошо, но все еще страдает от проблемы, на которую указал Жиль (в другом посте, который, похоже, был удален), что он работает, только если замена не содержит шаблон. Хотя мне нравится идея сценариев.
Кевин

Вещь красоты!
епископ

1

Я думаю, что это может работать, замените сначала, затем повторите 2 раза:

:s/a/b/
2@:
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.