2013-05-17 32 views
1

我有分析日志文件,在几行都会有它的重复自己,但不完全重复的线路,说Vim的:如何删除重复的

Alex is here and Alex is here and we went out 
We bothWe both went out 

我想删除第一个出现,并得到

Alex is here and we went out 
We both went out 

请分享一个正则表达式在Windows中做Vim。

回答

3

我不建议尝试使用正则表达式的魔法来解决这个问题。只需编写一个外部过滤器并使用它。

这是用Python编写的外部过滤器。您可以使用此预先处理的日志文件,像这样:

python prefix_chop.py logfile.txt > chopped.txt 

但它也可以由标准输入:

cat logfile.txt | prefix_chop.py > chopped.txt 

这意味着你可以在vim与!命令中使用它。到最后一行通过外部程序prefix_chop.py从当前行转到1号线,然后通过管道:

1G 
!Gprefix_chop.py<Enter> 

或者你也可以从EX模式做到这一点:

:1,$!prefix_chop.py<Enter> 

这里的程序尝试键入以下命令:

#!/usr/bin/python 

import sys 
infile = sys.stdin if len(sys.argv) < 2 else open(sys.argv[1]) 

def repeated_prefix_chop(line): 
    """ 
    Check line for a repeated prefix string. If one is found, 
    return the line with that string removed, else return the 
    line unchanged. 
    """ 
    # Repeated string cannot be more than half of the line. 
    # So, start looking at mid-point of the line. 
    i = len(line) // 2 + 1 

    while True: 
     # Look for longest prefix that is found in the string after pos 0. 
     # The prefix starts at pos 0 and always matches itself, of course. 
     pos = line.rfind(line[:i]) 
     if pos > 0: 
      return line[pos:] 
     i -= 1 

     # Stop testing before we hit a length-1 prefix, in case a line 
     # happens to start with a word like "oops" or a number like "77". 
     if i < 2: 
      return line 

for line in infile: 
    sys.stdout.write(repeated_prefix_chop(line)) 

我把第一行一个#!评论,所以这将工作在Linux,Mac OS X或Windows上,如果你使用的是C一个独立的程序ygwin。如果您只是在没有Cygwin的情况下使用Windows,则可能需要创建批处理文件才能运行此操作,或者只需键入整个命令python prefix_chop.py即可。如果你制作一个宏来运行它,你不必自己打字。

编辑:这个程序很简单。也许它可以在“vimscript”中完成,并纯粹在vim中运行。但是外部过滤器程序可以在vim之外使用...您可以进行设置,以便日志文件在每天每天运行一次,如果您愿意的话。

+0

嗨,你的解决方案工作,有一个角落的情况下,行的一个子集匹配自己,但它不需要切碎。我将if条件修改为'code'if pos> 0和line.rfind(line [:pos-1]):'code'以确保完整的线路存在而不是子集(我忘记提及,虽然) – SetV

+0

我很高兴它为你工作。你找到的角落案例就是为什么我犹豫是否将其作为纯粹的正则表达式解决方案犹豫不决......这是某种类型的问题,从某种程序中受益,因此您可以调整它,直到角落案例正常工作。 – steveha

0

你可以通过在行首开始尽可能地匹配,然后使用反向引用来匹配重复的位。

例如,该命令可以解决的问题,您描述:

:%s/^\(.*\)\(\1.*\)/\2 
+1

我想出了类似的东西。但是你的命令只能重复一次。例如OP问题中的例子。你可以做'%s/\ v(。*)\ 1 +(。*)/ \ 1 \ 2 /'之类的东西,但是由于贪婪规则,这只适用于偶数次重复。例如'ab ab ab ab xxx'(重复3次)将不起作用。因为最长的模式将是'ab ab'。 – Kent

+0

@亲爱的你把'。*'转换成'。+?',它可以用于偶数次重复..ie'\ b(。+?)\ 1+ \ b',并用' $ 1' – Anirudha

+0

''*''也会代替'l'你好..你应该在它后面用'\ b' – Anirudha

1

正则表达式:\b(.*)\1\b

替换为:\1$1

如果要处理超过两个重复的句子你可以试试这个

\b(.+?\b)\1+\b 
     -- 
     |->avoids matching individual characters in word like xxx 

注意

使用\<\>代替\b

+0

虽然不是vim正则表达式,但这个想法很有效。 (这个问题也用正则表达式标记) – Kent