我有一个大约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中的第二个解决方案中所建议的那样当我点击全部删除时,它会删除所有行,我得到一个空白文件文本,我做错了什么?
答案 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)))
- 负向前瞻以确保该行不是空行或该行不包含单词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
第二次点击替换后,行[{1}}也会被删除,只剩下B
行和C
行,如下所示:
第3次点击替换后,行[{1}}也会被删除,只留下行D
。
第4次点击替换后,行C
也被删除,没有留下这样的重复行
答案 2 :(得分:1)
awk '(a[$0]++==0)||(/Nivea|stime/)' file
(a[$0]++==0)
- a[$0]
(字典名为 a ,带有字符串' s字符串),++
增量值增加1(默认情况下未初始化的值eq 0),==0
- 检查第一次看到$0
(行)(检查等式后值是否更新/递增)
(/Nivea|stime/)
- 行列出了一个单词" Nivea"或" stime"
||
如果1 或 2中的一个为真,那么分析的行将被打印到屏幕