Как найти и удалить повторяющиеся строки из файла с помощью регулярных выражений?
Этот вопрос предназначен для языковой независимости. Могу ли я найти и заменить повторяющиеся строки в файле, используя только регулярные выражения?
Пожалуйста, рассмотрите следующий пример ввода и вывод, который я хочу;
Ввод >>
11
22
22 <-duplicate
33
44
44 <-duplicate
55
Выход >>
11
22
33
44
55
3 ответа
В Regular-expressions.info есть страница, посвященная удалению повторяющихся строк из файла.
В основном это сводится к поиску этого oneliner:
^(.*)(\r?\n\1)+$
... и заменить на \1
,
Примечание: точка не должна совпадать с Newline
Объяснение:
Каретка будет соответствовать только в начале строки. Таким образом, механизм регулярных выражений будет только пытаться сопоставить оставшуюся часть регулярного выражения. Комбинация точка и звезда просто соответствует целой строке, независимо от ее содержимого, если оно есть. Скобки сохраняют совпавшую строку в первую обратную ссылку.
Далее мы сопоставим разделитель строк. Я поставил знак вопроса в
\r?\n
чтобы заставить это регулярное выражение работать с обеими Windows (\r\n
) и UNIX (\n
) текстовые файлы. Таким образом, до этого момента мы сопоставляли строку и следующий разрыв строки.Теперь нам нужно проверить, сопровождается ли эта комбинация дубликатом той же строки. Мы делаем это просто с
\1
, Это первая обратная ссылка, которая содержит линию, которую мы сопоставили. Обратная ссылка будет соответствовать тому же самому тексту.Если обратная ссылка не совпадает, совпадение с регулярным выражением и обратная ссылка отбрасываются, и механизм регулярного выражения повторяет попытку в начале следующей строки. Если обратная ссылка завершается успешно, символ плюса в регулярном выражении будет пытаться сопоставить дополнительные копии строки. Наконец, символ доллара заставляет механизм регулярных выражений проверять, является ли текст, соответствующий обратной ссылке, полной строкой. Мы уже знаем, что тексту, которому соответствует обратная ссылка, предшествует разрыв строки (соответствует \r?\ N). Таким образом, теперь мы проверяем, следует ли за ним также разрыв строки или он находится в конце файла, используя знак доллара.
Весь матч становится
line\nline
(или жеline\nline\nline
так далее.). Поскольку мы выполняем поиск и замену, все строки, их дубликаты и разрывы между ними удаляются из файла. Поскольку мы хотим сохранить исходную строку, а не дубликаты, мы используем\1
в качестве текста замены, чтобы вернуть исходную строку.
Смотрите мой запрос для получения дополнительной информации, я отвечаю простым способом сейчас.
Если порядок не имеет значения, просто
сортировать -у
сделает свое дело
Если порядок имеет значение, но вы не против перезапустить несколько проходов (это синтаксис vim), вы можете использовать:
% S /\(.*\)\(\_.*\)\(\1\)/\2\1/ г
чтобы сохранить последнее вхождение, или
% S /\(.*\)\(\_.*\)\(\1\)/\1\2/ г
сохранить первое вхождение.
Если вы не возражаете, запустите несколько проходов, чем это сложнее, поэтому, прежде чем мы будем работать над этим, скажите, пожалуйста, в вопросе!
РЕДАКТИРОВАТЬ: в вашем редактировании вы были не очень ясны, но похоже, что вам нужно всего лишь однократное удаление дублирующих строк ADJACENT! Ну, это намного проще!
Просто:
/(.*)\1*/\1/
(/\(.*\)\1*/\1/
в vim) т.е. ищу (.*)\1*
и заменить его просто \1
сделает свое дело
В RegexBuddy вы можете сделать это следующим образом:
- На вкладке Библиотека загрузите библиотеку RegexBuddy.rbl, если она не загружена по умолчанию.
- В поле поиска введите "дубликат"
- Нажмите кнопку "Использовать", чтобы загрузить регулярное выражение "удалить дубликаты".
- На вкладке GREP укажите папку и маску файлов, из которых вы хотите удалить дубликаты.
- В раскрывающемся меню кнопки GREP выберите Выполнить.
Если вы делаете это только для одного файла, вы можете использовать вкладку "Тест" вместо вкладки "GREP". Загрузите файл на вкладку "Тест" и нажмите кнопку "Заменить" на главной панели инструментов.