Как извлечь совпадения регулярных выражений с помощью Vim - PullRequest
16 голосов
/ 31 января 2012

Пример:

case Foo:
    ...
    break;
case Bar:
    ...
    break;
case More: case Complex:
    ...
    break:
...

Я бы хотел получить все совпадения с регулярным выражением (весь соответствующий текст или, что еще лучше, часть между \( и \)) из RegEx case \([^:]*\):, которая должна давать что-то вроде (в новом новом файл):

Foo
Bar
More
Complex
...

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

Есть ли простой способ отобразить все совпадения RegEx и поместить их в буфер в Vim ?

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

Ответы [ 4 ]

24 голосов
/ 31 января 2012

Существует общий способ сбора шаблонных совпадений на протяжении всего произведения. текста. Техника использует замену с функция выражения команды :substitute (см. :help sub-replace-\=). Основная идея заключается в использовании замены перечисление всех совпадений с образцом для оценки сохранения выражения их без замены.

Во-первых, давайте рассмотрим сохранение матчей. Чтобы сохранить последовательность из соответствующих фрагментов текста, удобно использовать список (см. :help List). Тем не менее, невозможно изменить список напрямую, используя команду :let, так как нет способа запускать команды Ex в выражениях (включая \= замещающие выражения). Тем не менее, мы можем вызвать одну из функций, которые изменяют список на месте. За Например, функция add() предназначена для добавления данного элемента в указанный список (см. :help add()).

Другая проблема заключается в том, как избежать изменения текста во время работы замена. Один из подходов состоит в том, чтобы шаблон всегда имел совпадение нулевой ширины с добавлением \ze или добавлением \zs атомов к нему (см. :help /\zs, :help /\ze). Шаблон, измененный таким образом захватывает пустую строку, предшествующую или последующую вхождению исходный шаблон в тексте (такие совпадения называются совпадения нулевой ширины в Vim; см :help /zero-width). Затем, если текст замены также пусто, замена фактически ничего не меняет: она просто заменяет совпадение нулевой ширины с пустой строкой.

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

Объединяя вышеупомянутые идеи, мы получаем следующую команду Ex.

:let t=[] | %s/\<case\s\+\(\w\+\):\zs/\=add(t,submatch(1))[1:0]/g

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

Ctrl + R =t Введите

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

:pu=t
2 голосов
/ 01 февраля 2012

Хотя невозможно написать однострочник для выполнения вашего примера, сложно набирать такие команды, как :%s/case \([^:]*\):/\=.../ в интерактивном режиме.

Я предпочитаю использовать vim-grex сследующие шаги:

  1. Используйте /, чтобы проверить, соответствует ли регулярное выражение ожидаемым строкам.Например: /^\s*\<case\s\+\([^:]*\):.*$<Enter>
  2. Выполнить :Grey.Выдергивает строки, соответствующие текущему шаблону поиска.
  3. Открыть новый буфер с помощью :new и т. Д.
  4. Поместить восстановленные строки на p и т. Д.
  5. Обрезать неинтересночасти по :%s//\1/.
1 голос
/ 17 января 2019

Как использовать vim regex для извлечения слова из следующей строки, учитывая, что «помощь» может быть любым словом, например «ржавчина» или «perlang».

vim:tw=78:ts=8:ft=help:norl:

Решение:

let foo = substitute(foo, '^\s*vim:.*:ft=\([a-z]\+\).*:\s*$', '\1', '')
echo "foo: '" . foo . "'"

Отпечатки:

foo: 'help'

Медитация Гуру: что здесь происходит?

Возьмите строку в переменной foo и сопоставьте ее, чтобы указать начало строки, затем любое количество пробелов, литерал vim и буквенное двоеточие, затем любое количество любых символов, за которыми следует двоеточие ft= с любым словом с буквами, затем с чем угодно и утверждать, что строка заканчивается двоеточием.Бросьте все это в регистр с именем 1, затем верните это обратно в параметр 2, который принимает substitute и заменяет предыдущую строку на.

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

0 голосов
/ 31 января 2012
:g/^case\s\L\l\+\scase.*/s/case/\r&/g
:let @a=''|g/^case\s\L\l\+:/y A

Теперь откройте новый буфер или файл tmp и примените:

"ap
:%s_^\vcase ([^:]+):_\1_

Или, если вам не нужен текущий буфер (вы, конечно, можете отменить это) (обновлено для сложного примера):

:g/^case\s\L\l\+\scase.*/s/case/\r&/g
:v/^case\s\L\l\+:/d
:%s_^\vcase ([^:]+):_\1_
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...