1

Как удалить строку, содержащую соответствующий шаблон и следующие n строк, используя инструмент, поддерживающий регулярные выражения?

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

Например, если у меня есть соответствующий шаблон bbbb и я хочу также удалить следующие 5 строк для входного файла:

aldjflajdkl
aaaabbbbaaaa
1l;adfjl
2aldfjl
3adlflkdas
4aldfjd
5aldfkld
6dlafjlkdas

Выход будет:

aldjflajdkl
6dlafjlkdas

Возможно, это упростит то, что в моем конкретном случае не может быть, чтобы соответствующий шаблон (bbbb) содержался в следующих 5 строках.

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

2 ответа2

2

Возможное решение:

.*<matching pattern>(.*\r?\n){<N+1>}

где N - количество строк, которые я хочу удалить после строки, содержащей шаблон.

Для приведенного примера это означает:

.*bbbb(.*\r?\n){6}

Вот как это выглядит в grepWin:скриншот grepWin
Примечания стороны:

  • На вкладке "Соответствие строки поиска по регулярному выражению" также отмечается, что строка 5aldfkld помечается как совпадающая, на самом деле полоса прокрутки видна справа
  • (специфично для grepWin) Из-за небольшой ошибки при применении этого поиска к файлам количество совпадений увеличивается на 7 для каждого совпадения! Вероятно, это потому, что счетчик совпадений подсчитывает, сколько строк соответствует, и в этом случае шаблон охватывает 7 строк: совпавшую строку, следующие 5 строк и строку, достигнутую с последним переводом строки.
  • (специфично для sed) Это регулярное выражение не работает для sed , который не полностью поддерживает регулярное выражение и не имеет простого способа сопоставления / замены новых строк.

Ниже объясняется, как я попал к решению.

Я начал с:

.*bbbb.*\n.*\n.*\n.*\n.*\n.*\n

который не будет работать в моей системе. Но следующее будет работать:

.*bbbb.*\r\n.*\r\n.*\r\n.*\r\n.*\r\n.*\r\n

Итак, я работаю в системе CRLF. Однако это не выглядит ни красиво, ни портативно.

Я могу сделать его немного более портативным (и уродливым :-)), выполнив:

.*bbbb.*\r?\n.*\r?\n.*\r?\n.*\r?\n.*\r?\n.*\r?\n

(Возврат каретки становится необязательным). Это все еще выглядит некрасиво, но я могу собрать повторяющийся термин:

.*bbbb(.*\r?\n){6}

Это руководство было очень удобным.

1

Решение awk :

awk '/bbbb/ {i=5; next} {if (i>0) i--; else print}'

Когда он обнаруживает шаблон, который вы ищете, он устанавливает для i (который является счетчиком обратного отсчета) значение 5 и пропускает оставшуюся часть обработки (т.е. переходит к следующей строке ввода).  В частности, он не печатает строки.  (Сказать /bbbb/ {i=5+1} для первой части было бы эквивалентно; выберите тот, который основан на ваших предпочтениях стиля.)  Затем, если счетчик положительный, уменьшите его (вычтите 1), чтобы сосчитать удаляемые (пропущенные) строки, и не печатать; в противном случае выведите строку.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .