Regular-Expression

vim 正則表達式搜尋和替換

  • November 3, 2017

我正在嘗試替換文件中的部分字元串

例如,我有一個 csv 文件。

r1,col1,col2,35,000,col4,col5
r2,col1,col2,1,000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4,325.33,col4,col5

本質上我想用上面的 col3 替換 , 。在保留前 x 個數字的同時,它看起來如下所示:

r1,col1,col2,35000,col4,col5
r2,col1,col2,1000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4325.33,col4,col5

通常我會執行

:%s/\,[0-9]*\,/\,\1/g

但是當我跑步時,我得到了

r1,col1,col2,000,col4,col5
r2,col1,col2,000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,325.33,col4,col5

我應該在替換的第二部分使用什麼,以便獲得所需的輸出。

可能想要:%s/\v(([^,]*,){3})([0-9]+),([0-9])/\1\3\4/.

您的目標是從第四個欄位中刪除逗號(如果存在),而不刪除其他地方的逗號並且不刪除任何其他文本。複雜的因素是逗號也用作欄位分隔符。要解決這個問題,您必須考慮您對逗號可以出現在欄位中的條件的了解。畢竟,沒有任何進一步的限制,您的記錄是模棱兩可的。

很容易將任何跨越兩位數的逗號視為可以刪除,但這不起作用。您的範例輸入顯示您可以讓一個欄位以數字結尾,而下一個欄位以一個 ( col2,35,000) 開頭。

如果您知道前三個欄位本身不包含逗號,那麼問題就會變得容易得多,因為在刪除任何逗號之前,可以跳過前三個零個或多個非逗號後跟逗號的序列。那麼問題就變成瞭如何確定第四個欄位何時結束。您應該問自己是否要從第四個欄位中刪除多個逗號,或者是否始終沒有逗號或一個逗號。

為了這個答案,我假設第四個欄位最多包含一個應該刪除的逗號。我將進一步假設逗號出現在一位或多位數字之後和至少一位數字之前。然後你可以在 Vim 中使用它:

:%s/\v(([^,]*,){3})([0-9]+),([0-9])/\1\3\4/

或者,如果您更喜歡使用 Sed:

sed -r 's/(([^,]*,){3})([0-9]+),([0-9])/\1\3\4/' *filename*.csv

這個怎麼運作

正則表達式(([^,]*,){3})匹配前三個欄位和後面的欄位分隔符,所有這些都需要保持不變。[^,]匹配除 a 以外的任何單個字元,。之後它會導致它們中的*零個或多個匹配,而不是恰好匹配一個。,之後匹配該非逗號欄位後面的實際逗號。這都是分組的,( )並且{3}應用於它會導致它匹配三次而不是一次。然後整個內容分組,以便可以使用\1. (內部組也擷取並可以作為訪問\2。)

然後([0-9]+)匹配一個或多個 ( +) 數字 ( [0-9]) 並擷取匹配 ( ( )) 以便可以將其訪問為\3. ,字元匹配文字逗號;這是我們不會保留的部分。然後([0-9])擷取一個數字,以便它可以作為\4.

\1您可以通過對and使用單個組來使正則表達式更簡單一些\3,即(([^,]*,){3}[0-9]+). 我已經避免了,因為我覺得它隱藏了你的記錄的結構——它們是由逗號分隔的欄位組成的——但是這樣做並沒有錯。如果你這樣做了,\4就會變成\3,所以在替換模式中你會使用\1\3而不是\1\3\4.

最後,\vVim 正則表達式的開頭並-r傳遞給sed服務以允許您使用擴展的正則表達式語法。這就是為什麼我能夠寫(and)而不是\(and \),而+不是\+.

引用自:https://unix.stackexchange.com/questions/402145