【问题标题】:Remove specific duplicate lines without sorting删除特定的重复行而不进行排序
【发布时间】:2018-02-10 14:56:14
【问题描述】:

我有一个大约 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”的行,然后按照this post 中的第二个解决方案中的建议在搜索和替换对话框中使用此正则表达式 ^(.*?)$\s+?^(?=.*^\1$),当我点击全部替换,它删除了所有行,我得到一个空白文件文本,我做错了什么吗?

【问题讨论】:

  • 请发布预期输出。
  • 完成,我在帖子中添加了预期的结果。
  • 需要使用notepad++吗?
  • notepad++ 只是一个编辑器,即使它有高级功能,也不是处理数据的工具。

标签: regex notepad++


【解决方案1】:

使用 awk

  awk '(a[$0]++==0)||(/Nivea|stime/)' file
  1. (a[$0]++==0) - a[$0](名为 a 的字典,其键为行字符串),++ 将值递增 1(默认值未初始化 eq 0),@987654326 @ - 检查$0(行)是否第一次出现(在检查方程式后更新/增加值)

  2. (/Nivea|stime/) - 行在列表中包含“Nivea”或“stime”一词

  3. || 如果 1 2 之一为真,则分析的行将打印到屏幕上

【讨论】:

【解决方案2】:

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

因此,您必须坐在一个循环中,从头开始重新开始
字符串,直到所有 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)

【讨论】:

    【解决方案3】:

    下面的正则表达式可以正常工作但要使其正常工作,必须多次点击替换按钮。例如,在 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 组中捕获的行的重复。

    我可以通过下面的多个屏幕截图更好地解释它:

    在进行一次替换之前,我的文件如下所示:

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


    第一次点击替换后,A 行被删除,只剩下BCD


    第二次点击替换后,B行也被删除,只剩下CD行,如下图:


    第三次点击替换后,C 行也被删除,只剩下D 行。


    第四次点击替换后,D行也被删除,不再留下重复的行

    【讨论】:

      猜你喜欢
      • 2012-07-16
      • 2011-02-13
      • 1970-01-01
      • 2016-03-17
      • 2010-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多