Как искать шаблон с помощью фигурных скобок и добавлять/удалять из шаблона?

Я не могу найти, как решить это:

Я пытаюсь найти шаблон p.e. 'test' с помощью фигурных скобок
p.e. test\{2,}

Я хочу добавить или удалить один и тот же шаблон с помощью диалогового окна ввода.

т.е.
найти слово test {2,} раз и удалить 1 тест из совпадения
или найти слово test {2,3} раз и удалить 2 x тест из совпадения
или найти слово test {, 2} раза и добавить 2 х теста, чтобы соответствовать

Я не могу найти регулярное выражение, которое бы делало то, что мне нужно.
Кто-нибудь знает решение?

РЕДАКТИРОВАНИЕ
Возможно, разделение строки подсовпадения в списке является решением и подсчитывает количество совпадений (длину списка).
p.e. поиск test\{2,5} и удаление 2 x test:

%s/\(test\)\@<!\(test\)\{2,5}\(test\)\@!/\=repeat(submatch(2), len(split(submatch(2), 'test'))-2)/g

но это не работает. Что я сделал не так?


person Reman    schedule 02.08.2013    source источник
comment
Используйте (test){2} (и т. д.), чтобы сопоставить вхождения всего слова. Поскольку круглые скобки окружают только одно слово, вы можете использовать \1 (или его местный эквивалент) в выражениях замены.   -  person Jongware    schedule 02.08.2013


Ответы (3)


Вам нужно заключить строку (test) в экранированные круглые скобки, чтобы она работала как единое целое. Это дает вам \(test\)\{2,}, который найдет testtest, testtesttest и т. д.

Чтобы заменить это только одним test, попробуйте следующее:

:%s/\(test\)\{2,}/\1/g

Это ищет 2 или более повторений test и использует \1 для замены его одним экземпляром строки поиска.

Точно так же для вашего второго запроса просто введите 3:

:%s/\(test\)\{2,3}/\1/g

А для третьего запроса просто вставьте больше копий \1, чтобы получить желаемый результат:

:%s/\(test\)\{,2}/\1\1\1/g

person pattivacek    schedule 02.08.2013
comment
Вы правы насчет отсутствующих скобок, но синтаксис Vim для диапазонов соответствия действительно \{n,m}; в отличие от других диалектов регулярных выражений, таких как sed. - person Ingo Karkat; 02.08.2013
comment
@IngoKarkat Странно; это кажется необязательным в vim. Я никогда не знал. Я отредактирую свой пост. - person pattivacek; 02.08.2013
comment
например 2-й запрос. если бы у меня было testtest, замененный результат был бы "" пустой строкой. если я правильно понял. - person Kent; 02.08.2013
comment
@Кент, возможно, ты прав. Это будет :%s/\(test\)\{2}\(test\)\?/\2/g - person pattivacek; 02.08.2013
comment
Если это важно для вас, вы можете избавиться от множества этих обратных косых черт, используя атом \v. Таким образом, для первого регулярного выражения patrickvacek эквивалентным выражением будет :%s/\v(test){2,}/\1/g, что немного легче читать IMO. - person ravron; 02.08.2013
comment
@patrickvacek, спасибо за ответ. Однако это не совсем то, что я хочу. Я хочу не заменить его 1 тестом или 3 тестами, а удалить 1 тест из матча. п.э. 1-й пример. Если есть совпадение 4-кратного теста, он должен вернуть 3-кратный тест (удалить 1-кратный тест). Если есть совпадение 3-кратного теста, он должен вернуть 2-кратный тест (убрать 1-кратный тест). - person Reman; 02.08.2013
comment
@Remonn, я думаю, что лучше понимаю твое намерение, но мне придется продолжать думать об этом, чтобы посмотреть, смогу ли я найти чистый способ сделать это. У меня ничего не выходит из головы; Я не думаю, что есть собственный механизм для повторения подобных замен. - person pattivacek; 02.08.2013

Если я правильно понимаю ваше требование, ответ может помочь.

Я бы использовал test(space) в примерах, а в примере есть пробел в конце

  • найти слово test {2,} раз и удалить 1 тест из совпадения
[before ]test test foo test test test foo test 
[command]s/\v(test )(\1+)/\2/g
[after  ]test foo test test foo test 
  • найти слово test {2,3} раза и удалить 2 x test из совпадения
[before ]test test foo test test test foo test 
[command]s/\v(test ){2}(\1?)/\2/g
[after  ]foo test foo test 
  • найти слово test {,2} раз и добавить 2 x test для соответствия
[before ]test test foo test test test foo test 
[command]s/\v(test ){,2}/&\1\1/g
[after  ]test test test test foo test test test test test test test foo test test test 
person Kent    schedule 02.08.2013
comment
Спасибо, Кен, ты нашел ответ на мои примеры. Что я хотел бы сделать, так это найти общее регулярное выражение, которое работает в каждом примере. Нет ли способа обобщить регулярное выражение? (Я хочу использовать диалоговое окно ввода для вставки. Например, найти test\{2,5} и удалить 2x test из совпадения или любого другого примера. Я пробовал это с частичными совпадениями, но это не сработало, как я хотел. Проблема в том, что я не не знаю, сколько раз есть совпадение с test - person Reman; 02.08.2013
comment
@Remonn Я сомневаюсь, что существует общая команда regex/:s, которая делает то, что вы хотите. однако вы можете анализировать ввод пользователя, например. test{2,5} and remove 2x, чтобы сгенерировать команду :s. или генерировать разные аргументы для substitute(). для этого примера пользователь хочет удалить 2x, поэтому нам интересно 2, нам нужно s/\v(foo){2}..., а пользователь дал {2,5}, вы должны сравнить нижнюю границу (2) и ввод удаления (2), в этом случае они такой же. так что 5-2=3 у нас есть s/\v(foo){2}(\1{,3})/\2/g - person Kent; 02.08.2013
comment
Кент, спасибо. Первый {2} — это нижняя граница, а фигурные скобки после \1 — это {2,5} - 2 = {,3}? Надеюсь это работает. Постараюсь протестировать еще несколько примеров как {1,3} :) - person Reman; 02.08.2013
comment
Хм, не работает с {1,3} .. Другое решение, о котором я думаю, - это разделить совпадения в списке (разделив на поиск (тест) и подсчитать количество записей в списке. Возможно ли это? - person Reman; 02.08.2013

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

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

регулярное выражение:

%s/\(test\)\@<!\(test\)\{2,5}\(test\)\@!/\=repeat(submatch(2), len(split(submatch(0), '\ze'.submatch(2)))+2)/g

объяснение:

  • поиск test от 2 до 5 раз, но не в строке, содержащей более test:

    \(test\)\@<!\(test\)\{2,5}\(test\)\@!

  • найдите, сколько раз test встречается во всем совпадении:

    len(split(submatch(0), '\ze'.submatch(2))

    разделение всего матча на номер. одиночных совпадений и подсчитайте одиночные совпадения

    подсовпадение(0) = множественное "тест" (полное совпадение)
    подсовпадение(2) = "тест"

  • повторить номер. совпадений из всего совпадения и добавить или удалить из него:

    \=repeat(submatch(2), len(split(submatch(0), '\ze'.submatch(2)))+2)

person Reman    schedule 03.08.2013