2012-06-13 51 views
4

使用VI替換第一次出現/實例非常簡單。每行第一次出現vi/vim/sed等

:%s/search/replace/args 

但是,這裏以.csv格式/文件中設置我的數據:

"192.168.2.1","www.google.com","2009/01/11_10:00"," What a great website" 
"192.168.2.2/driving/is/fun","-","2009/03/22_00:00","Driving website" 
"192.168.2.4/boating/is/crazy","-","2009/03/22_00:00","Boating Website" 
"192.168.2.5","www.cars.com","2009/04/27_00:00","What a good car website" 

所以,你會在第一行注意到,有4列,這是理想的線爲.csv格式。

但是,在第二行中,有4列,但第一列只接受IP地址,只有192.168.2.2/driving/is/fun必須被刪除或與「,」.csv分開delimter。

在六,我可以使用以下命令:

:/^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//s/\//","/ 

其執行以下操作:

  • /^"\d{,3}.\d{,3} 。\ d {,3}。\ d {,3}/- 設置一個錨點以在第一個IP上以正斜槓/開始搜索。例如,第2行:「192.168.2.2/

  • /s ///「,」/ - 替換IP地址末尾的/並用.csv分隔符替換它「, 「

這在VI/VIM中很好用,一次代替我需要的一行。但是,數據集要大得多,並且手動使用以下的vi搜索和替換非常耗時。我正在尋找它的腳本或找到一個替代解決方案,因爲VI/VIM將一次只做一行,如下所示:s/search/replace/g另外替換每行/更改日期列。

很顯然,我已經試過如下:

添加%整個文件內部置換開始的像這樣:

:/^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//%s/\//","/ 

其中突出的每個條目我需要修改,但出錯:

E492: Not an editor command: /^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//%s/\// 

這很讓人困惑。

我最終想用sed/perl腳本編輯整個文件。

所以..

「192.168.2.2/ - > 」192.168.2.2「,」 在每一行

第一次出現。

任何幫助將不勝感激..

謝謝!

+2

只是一個普通的protip:你可以使用幾乎任何字符來分隔你的模式。例如,如果您使用管道,則不必跳過斜槓。 – qwertyboy

回答

3

在vim,嘗試:

:%s/^\("\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\)\(\/[^"]\)/\1","\2 

也就是說,而非搜索/替換我使用全局(%是來自第一線1,$快捷最後一行)替代。我將你的搜索模式轉移到替換模式中,並在不同的組中分別捕獲IP地址和路徑。然後將它們重新放回,擠壓其間的","

+0

不錯的工作..完美..你能解釋我錯過了什麼,或者你已經添加了什麼,只是讓我明白/學習? – SecurettyPhreak

+0

我在答案中添加了它。如果我能進一步澄清,請告訴我。 – PEZ

+0

PEZ,我明白%=全球,但分組和使用「背擠」並不適合我。我知道你做了什麼,我發現它有用。我只需要了解語法是如何讀/使用等的。我不完全理解這部分是如何工作的:\(\/[^「] \)/ \ 1」,「\ 2因爲我想申請另一個假設我有IP「192.168.2.1:8080,並且需要使用」你「必須用」,「替代:」 – SecurettyPhreak

4

在vi/vim中,您可以指定要替換的搜索範圍。在這種情況下,你想:%s的所有線替換:

:%s/search/replace/g 

您還可以指定:

:2,5s/search/replace/g  Replace on lines 2-5 
:.,$s/search/replace/g  Replace from current line (.) to last line ($) 
:.,+3s/search/replace/g  Replace on the current line (.) and the two next lines (+3) 
:g/^asd/s/search/replace/g Replace on lines starting with 'asd'. 

然後,您可以用更簡單的方式結合這在整個文件進行所需的替換:

:%s/^\("[^/"]*\)[^"]*"/\1"/ 

這將刪除CSV中第一個條目的IP地址後的所有內容。

:%s/^\("[^/"]*\)\/\([^"]*\)"/\1","\2/ 

這會將第一個條目分割爲IP地址和其餘部分,但這隻會在IP後面有斜線的那些行中完成。 你試圖做的是找到模式,去那條線,然後取代。在這種情況下添加'%'使命令無效。

+0

John Lawrence,謝謝你的回覆..「(:%s/search/replace/g)」不起作用。當使用g-global選項時,它會刪除日期中的正斜槓,而不僅僅是IP末尾的正斜槓,它會取出文件中的每個斜槓。如果您只使用:%s,則會刪除目錄路徑和日期等行中的每個正斜槓。 – SecurettyPhreak

+0

這是正確的。添加'g'會替換該行中的所有匹配,而沒有它會替換第一個匹配。這就是爲什麼我把'g'留給你應該使用的正則表達式的原因。對不起,如果不清楚,我的答案的第一位是更多的一般參考。 –

+0

即使使用:%s/\ //「,」/第一次出現正斜槓時,會刪除IP後的沒有正斜槓的行項目上的正斜槓,從而導致第一次出現正斜槓在線的其他地方,如日期。 – SecurettyPhreak

2

你可以做你想做的一個簡單的模式:

s/^\("[^/"]*\)[^"]*"/\1"/ 

這就是:行的比賽開始,開始比賽組:匹配",匹配的是不是一個斜槓任何數量的字符不是",請關閉匹配組,匹配任何不是"的字符數,並匹配"。用匹配組內容替換"

上面的模式對腳本應該很簡單。這是一個Python示例。

#!/usr/bin/env python 
import re 
import sys 

if len(sys.argv) != 3: 
    print("Usage: log_file_cleaner <input_file> <output_file>") 
    sys.exit(1) 

pat = re.compile(r'^("[^/"]*)[^"]*"') 

with open(sys.argv[1]) as in_f, open(sys.argv[2], "w") as out_f: 
    for line in in_f: 
     line = re.sub(pat, r'\1"', line) 
     out_f.write(line) 

注意:您需要最新版本的Python做一個with做兩個open()電話。如果你被困在Cygwin上,你可以編輯上面的兩個嵌套的with語句,每個語句只需一個open()調用。

+0

steveha,謝謝你的回覆。 s/^ \(「[^ /」] * \)[^「] *」/ \ 1「/ ^^只突出顯示/選擇兩個」「之間的所有內容。 所以它突出顯示「192.168.2.1」和「192.168.2.2/driving/is/fun」 – SecurettyPhreak

+0

您是否瞭解匹配組是什麼以及它是如何工作的?是的,整個模式與「/ driving/is/fun」相匹配,但比賽組忽略了它。而且,如果您需要它在第一個引號之後拒絕空格,我可以編輯該模式來完成此操作,但您的示例並未表明這將是必需的。 – steveha