Удалить определенные повторяющиеся строки без сортировки

У меня есть текстовый файл с примерно 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
  1. (a[$0]++==0) - a[$0] (словарь с ключом строки), ++ увеличить значение на 1 (по умолчанию значение, которое не было инициализировано, например, 0), ==0 - Проверь это $0 (строка) была видна впервые (значение обновляется / увеличивается после проверки уравнения)

  2. (/Nivea|stime/) - строка включает в список одно из слов "Nivea" или "stime"

  3. || если один из 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 также удаляется и таких повторяющихся строк не осталось

введите описание изображения здесь

Другие вопросы по тегам