删除特定的重复行而不进行排序

时间:2018-02-10 14:56:15

标签: regex notepad++

我有一个大约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中的第二个解决方案中所建议的那样当我点击全部删除时,它会删除所有行,我得到一个空白文件文本,我做错了什么?

3 个答案:

答案 0 :(得分:3)

您需要脚本功能,因为无法删除
重复的行没有将匹配位置推进到该行

因此,你必须坐在一个循环中,从开头重新开始 字符串,直到删除所有dup。

示例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)

答案 1 :(得分:2)

以下正则表达式工作正常但要使其正常工作,必须多次点击替换按钮重复次数。例如,在OP的共享示例中,有4条这样的行需要替换,因此必须单击4次替换按钮。我知道这可能不是大文件的有效解决方案,但它是我对这个问题的最佳尝试。

^(?!(?:\s*$|.*(?:Niveau|stime)))(.*$)([\s\S]*?)(\1\s*)

将匹配项替换为\1\2

Here is the regex 演示,演示了仅替换第一个重复行。一个人必须多次重复这个替换,以摆脱每个重复行的所有期望。

正则表达式说明:

  • ^ - 断言行的开头
  • ^(?!(?:\s*$|.*(?:Niveau|stime))) - 负向前瞻以确保该行不是空行或该行不包含单词Niveaustime
  • (.*$) - 匹配并捕获组1中一行的内容。在第1组中,我们尝试捕获可能在文件后面某处重复的行。
  • ([\s\S]*?) - 匹配任何字符的0次出现,尽可能少并将其捕获为第2组
  • (\1\s*) - 匹配组1的内容,后跟0次出现的空格。如果存在这样的匹配,则在组3中捕获它。我们需要从文件中丢弃组3内容,因为它只是在组1中捕获的重复行。

我可以使用下面的多个屏幕截图

更好地解释它

在做一次替换之前,我的文件看起来像这样:

enter image description here

我们需要删除行ABCD。由于有4条这样的线,我们必须点击替换按钮4次,如下面几张截图所示。

第一次点击替换后,系列A被移除,只剩下BCD

enter image description here

第二次点击替换后,行[{1}}也会被删除,只剩下B行和C行,如下所示:

enter image description here

第3次点击替换后,行[{1}}也会被删除,只留下行D

enter image description here

第4次点击替换后,行C也被删除,没有留下这样的重复行

enter image description here

答案 2 :(得分:1)

使用awk

  awk '(a[$0]++==0)||(/Nivea|stime/)' file
  1. (a[$0]++==0) - a[$0](字典名为 a ,带有字符串' s字符串),++增量值增加1(默认情况下未初始化的值eq 0),==0 - 检查第一次看到$0(行)(检查等式后值是否更新/递增)

  2. (/Nivea|stime/) - 行列出了一个单词" Nivea"或" stime"

  3. ||如果1 2中的一个为真,那么分析的行将被打印到屏幕