Удалить определенные повторяющиеся строки без сортировки
У меня есть текстовый файл с примерно 5000 строк, я должен удалить определенные повторяющиеся строки (которые не содержат слова "Niveau" или "stime"), но сохраняя первое вхождение и без сортировки, текстовый шаблон выглядит следующим образом:
vide vide Time: stime 3:30 PM vide vide
NN NN NP stime LS NP NN NN
----------Niveau 1--------------
Time: | 0 | 263.0 | 266.0 | 0,0113
NP | 0 | 0.0 | 24885.0 | 1
3:30 | -0 | 104.0 | 120.0 | 0,1333
LS | -0 | 0.0 | 13134.0 | 1
PM | -1 | 134.0 | 238.0 | 0,437
NP | -1 | 0.0 | 24885.0 | 1
----------Niveau 2--------------
3:30 PM | -0 | 30.0 | 41.0 | 0,2683
3:30 NP | -0 | 133.0 | 55.0 | -1,4182
LS PM | -0 | 42.0 | 237.0 | 0,8228
LS NP | -0 | 0.0 | 2456.0 | 1
----------Niveau 3--------------
vide vide Time: stime 3:30 pm vide vide
NN NN NP stime LS NN NN NN
----------Niveau 1--------------
Time: | 0 | 263.0 | 266.0 | 0,0113
NP | 0 | 0.0 | 24885.0 | 1
3:30 | -0 | 104.0 | 120.0 | 0,1333
LS | -0 | 0.0 | 13134.0 | 1
pm | -1 | 38.0 | 54.0 | 0,2963
NN | -1 | 0.0 | 59511.0 | 1
----------Niveau 2--------------
3:30 pm | -0 | 9.0 | 9.0 | 0
3:30 NN | -0 | 36.0 | 24.0 | -0,5
LS pm | -0 | 22.0 | 52.0 | 0,5769
LS NN | -0 | 0.0 | 2658.0 | 1
----------Niveau 3--------------
Ожидаемые результаты:
vide vide Time: stime 3:30 PM vide vide
NN NN NP stime LS NP NN NN
----------Niveau 1--------------
Time: | 0 | 263.0 | 266.0 | 0,0113
NP | 0 | 0.0 | 24885.0 | 1
3:30 | -0 | 104.0 | 120.0 | 0,1333
LS | -0 | 0.0 | 13134.0 | 1
PM | -1 | 134.0 | 238.0 | 0,437
NP | -1 | 0.0 | 24885.0 | 1
----------Niveau 2--------------
3:30 PM | -0 | 30.0 | 41.0 | 0,2683
3:30 NP | -0 | 133.0 | 55.0 | -1,4182
LS PM | -0 | 42.0 | 237.0 | 0,8228
LS NP | -0 | 0.0 | 2456.0 | 1
----------Niveau 3--------------
vide vide Time: stime 3:30 pm vide vide
NN NN NP stime LS NN NN NN
----------Niveau 1--------------
pm | -1 | 38.0 | 54.0 | 0,2963
NN | -1 | 0.0 | 59511.0 | 1
----------Niveau 2--------------
3:30 pm | -0 | 9.0 | 9.0 | 0
3:30 NN | -0 | 36.0 | 24.0 | -0,5
LS pm | -0 | 22.0 | 52.0 | 0,5769
LS NN | -0 | 0.0 | 2658.0 | 1
----------Niveau 3--------------
Используя плагин Notepad++ и TextFX, я скрываю строки, содержащие слова "Niveau" и "stime", а затем использую это регулярное выражение ^(.*?)$\s+?^(?=.*^\1$)
в диалоге поиска и замены, как предлагается во втором решении в этом посте, когда я нажимаю заменить все, он удаляет все строки, я получаю пустой текст файла, я делаю что-то не так?
3 ответа
Вам понадобится возможность сценариев, потому что нет способа удалить
дубликат строки без продвижения позиции совпадения до этой строки.
Таким образом, вам придется сидеть в цикле, перезапускаясь с начала
Строка, пока все дубли не будут удалены.
Пример Perl while ( str ~= s/regex/$1/g ) {}
Это может быть сделано. Может потребоваться немного больше времени, но это выполнимо.
Во всяком случае, это регулярное выражение вам нужно сделать это.
Во всем мире:
найти (?m)((^[^\S\r\n]*?(?=\S)(?:(?!Niveau|stime).)+$)[\S\s]*?)^\2$(?:\r?\n)?
замещать $1
Делайте это до тех пор, пока во всем мире больше не будет совпадений (т.е. замен)
Разъяснение:
(?m) # Multi-line mode
( # (1 start), To be written back
( # (2 start), The line to test
^ # BOL begin of line
[^\S\r\n]*? # Spurious horizontal whitespace
(?= \S ) # Must be a non-whitespace ahead
(?: # Skip lines containing these
(?! Niveau | stime )
.
)+
$ # EOL end of line
) # (2 end)
[\S\s]*? # Anything up to the duplicate
) # (1 end)
^ \2 $ # The actual duplicate line
(?: \r? \n )? # Optional linebreak (if last line, then ok)
Обратите внимание на то, что теперь, как и в регулярном выражении, горизонтальные пробелы отсутствуют.
на BOL и EOL, поэтому текст должен быть точным.
Однако легко добавить дополнительную обрезку, если это необходимо.
Обновить
Более быстрая версия приведенного выше регулярного выражения использует \K
построить, чтобы упростить
замена.
Во всем мире:
найти (?m)(^[^\S\r\n]*?(?=\S)(?:(?!Niveau|stime).)+$)[\S\s]*?\K^\1$(?:\r?\n)?
Заменить '' (ничего)
Разъяснения
(?m) # Multi-line mode
( # (1 start), The line to test
^ # BOL begin of line
[^\S\r\n]*? # Spurious horizontal whitespace
(?= \S ) # Must be a non-whitespace ahead
(?: # Skip lines containing these
(?! Niveau | stime )
.
)+
$ # EOL end of line
) # (1 end)
[\S\s]*? # Anything up to the duplicate
\K # Disregard the match up to here
^ \1 $ # The actual duplicate line to be deleted
(?: \r? \n )? # Optional linebreak (if last line, then ok)
используя awk
awk '(a[$0]++==0)||(/Nivea|stime/)' file
(a[$0]++==0)
-a[$0]
(словарь с ключом строки),++
увеличить значение на 1 (по умолчанию значение, которое не было инициализировано, например, 0),==0
- Проверь это$0
(строка) была видна впервые (значение обновляется / увеличивается после проверки уравнения)(/Nivea|stime/)
- строка включает в список одно из слов "Nivea" или "stime"||
если один из 1 или 2 является истинным, анализируемая линия будет выведена на экран
Приведенное ниже регулярное выражение прекрасно работает, НО, чтобы заставить его работать, нужно нажимать кнопку замены столько раз, сколько повторений. Например, в общем примере от OP есть 4 такие строки, которые требуют замены, поэтому нужно нажать кнопку замены 4 раза. Я понимаю, что это не может быть эффективным решением для больших файлов, но это моя лучшая попытка решить этот вопрос.
^(?!(?:\s*$|.*(?:Niveau|stime)))(.*$)([\s\S]*?)(\1\s*)
Заменить спички на \1\2
Вот демонстрация регулярных выражений, которая иллюстрирует замену только 1-й повторяющейся строки. Нужно повторить эту замену несколько раз, чтобы избавиться от всех ожиданий в первую очередь от каждой повторяющейся строки.
Regex Объяснение:
^
- утверждает начало строки^(?!(?:\s*$|.*(?:Niveau|stime)))
- отрицательный взгляд, чтобы убедиться, что строка не является пустой строкой или строка не содержит словNiveau
или жеstime
(.*$)
- сопоставляет и захватывает содержимое строки в группе 1. В группе 1 мы пытаемся захватить строку, которая может иметь повторения где-то позже в файле.([\s\S]*?)
- соответствует 0+ вхождений любого персонажа, как можно меньше и захватывает его как группу 2(\1\s*)
- соответствует содержимому группы 1, за которым следует 0+ вхождений пробела. Если такое совпадение присутствует, запишите его в группу 3. Нам нужно отбросить содержимое группы 3 из файла, поскольку оно представляет собой не что иное, как повторение строки, захваченной в группе 1.
Я могу объяснить это лучше с несколькими скриншотами ниже:
Прежде чем сделать хотя бы одну замену, мой файл выглядит так:
Нам нужно удалить линии A
, B
, C
а также D
, Поскольку таких строк 4, мы должны нажать кнопку замены 4 раза, как показано на скриншотах ниже.
После нажатия на кнопку замены в первый раз, строка A
удаляется и только B
, C
а также D
осталось
После нажатия на кнопку заменить во второй раз, строка B
также удаляется и только строка C
а также D
остаются, как показано ниже:
После нажатия заменить в 3-й раз, строка C
также удаляется и только строка D
осталось.
После нажатия заменить в 4-й раз, строка D
также удаляется и таких повторяющихся строк не осталось