2013-05-17 29 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