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

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

Пожалуйста, рассмотрите ввод примера follwing и вывод, который я хочу;

Ввод >>

11
22
22  <-duplicate
33
44
44  <-duplicate
55

Выход >>

11
22
33
44
55

Ответы

Ответ 1

Regular-expressions.info имеет страницу Удаление повторяющихся строк из файла

Это в основном сводится к поиску этого oneliner:

^(.*)(\r?\n\1)+$

... И заменив на \1.
Примечание. Точка не должна соответствовать Newline

Пояснение:

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

Далее мы сопоставим разделитель строк. Я помещал вопросительный знак в \r?\n, чтобы это регулярное выражение работало с текстовыми файлами Windows (\r\n) и UNIX (\n), Таким образом, до этого момента мы сопоставляли строку и следующий разрыв строки.

Теперь нам нужно проверить, следует ли за этой комбинацией дубликат этой же строки. Мы делаем это просто с помощью \1. Это первая обратная ссылка, в которой содержится строка, которую мы сопоставляли. Обратная ссылка будет соответствовать тому же самому тексту.

Если обратная ссылка не подходит, совпадение регулярных выражений и обратная ссылка отбрасываются, а механизм регулярных выражений снова пытается в начале следующей строки. Если backreference удастся, плюс символ в регулярном выражении будет пытаться сопоставить дополнительные копии строки. Наконец, символ доллар заставляет механизм регулярных выражений проверять, соответствует ли текст, согласованный с обратной ссылкой, полной линией. Мы уже знаем, что текст, сопоставляемый с обратной связью, предшествует разрыву строки (согласованному\r?\N). Поэтому мы теперь проверяем, следует ли за ним также разрыв строки или если он находится в конце файла, используя знак доллар.

Весь матч становится line\nline (или line\nline\nline и т.д.). Поскольку мы выполняем поиск и замену, строка, ее дубликаты и разрыв строки между ними удаляются из файла. Поскольку мы хотим сохранить исходную строку, но не дубликаты, мы используем \1 в качестве заменяющего текста, чтобы вернуть исходную строку.

Ответ 2

См. мой запрос для получения дополнительной информации. Сейчас я отвечаю простым способом.

  • Если порядок не имеет значения, просто

    sort -u

    сделает трюк

  • Если заказ имеет значение, но вы не возражаете повторно запускать несколько проходов (это синтаксис vim), вы можете использовать:

    % s/\ (. * \)\(\ _. * \)\(\ 1 \)/\ 2\1/г

    чтобы сохранить последнее вхождение, или

    % s/\ (. * \)\(\ _. * \)\(\ 1 \)/\ 1\2/г

    чтобы сохранить первое вхождение.

Если вы не возражаете повторно запускать несколько проходов, чем это сложнее, поэтому, прежде чем мы будем работать над этим, скажите об этом в вопросе!

EDIT: в вашем редактировании вы не очень поняли, но похоже, что вы хотите удалить только однопроходные дубликаты ADJACENT! Ну, это намного проще!

Прост:

/(.*)\1*/\1/

(/\(.*\)\1*/\1/ in vim), то есть поиск (.*)\1* и замена его просто \1 сделает трюк

Ответ 3

В RegexBuddy вы можете сделать это следующим образом:

  • На вкладке "Библиотека" загрузите библиотеку RegexBuddy.rbl, если она не загружена по умолчанию.
  • В поле поиска введите "duplicate"
  • Нажмите кнопку "Использовать", чтобы загрузить регулярное выражение "delete duplicate lines".
  • На вкладке GREP укажите папку и маску файла для файлов, из которых вы хотите удалить дубликаты.
  • В раскрывающемся меню кнопки GREP выберите "Выполнить".

Если вы делаете это только в одном файле, вы можете использовать вкладку "Тест" вместо вкладки GREP. Загрузите файл на вкладке "Тест" и нажмите кнопку "Заменить" на главной панели инструментов.