2012-07-27 70 views
3

我的問題與shell script: search and replace over multiple lines類似的問題有一個小例外。正則表達式查找和替換殼牌中的多行

在問題鏈接的用戶要做到這一點:

source: 
[stuff before] 
<!--WIERD_SPECIAL_COMMENT_BEGIN--> 
    [stuff here, possibly multiple lines. 
<!--WIERD_SPECIAL_COMMENT_END--> 
[stuff after]  

target: 
[stuff before] 
[new content] 
[stuff after] 

我的問題是相似的,我想這樣做:

source: 
[stuff before] 
<!--WIERD_SPECIAL_COMMENT_BEGIN--> 
    [this] 
<!--WIERD_SPECIAL_COMMENT_END--> 
<!--WIERD_SPECIAL_COMMENT_BEGIN--> 
    [not this] 
<!--WIERD_SPECIAL_COMMENT_END--> 
[stuff after]  

target: 
[stuff before] 
[new content] 
<!--WIERD_SPECIAL_COMMENT_BEGIN--> 
    [not this] 
<!--WIERD_SPECIAL_COMMENT_END--> 
[stuff after] 

在一個適當的多正則表達式,這是很容易做到:

/<!--WIERD_SPECIAL_COMMENT_BEGIN-->.*[this].*<!--WIERD_SPECIAL_COMMENT_END-->/m 

但在鏈接問題中建議的答案使用正則表達式作爲不允許檢查的範圍兩個邊界之間的界限。

是否有任何方法可以將一個範圍內的所有行添加到模式緩衝區,以便我可以一次對所有行進行regex?例如:

sed ' 
    #range between comment beginning and comment end 
    /<!--WIERD_SPECIAL_COMMENT_BEGIN-->/,/<!--WIERD_SPECIAL_COMMENT_END-->/ 
    #Do something to add the lines in this range to pattern buffer 
    /.*[this].*/d 
    #Delete all the lines if [this] is in the pattern buffer 
' <in.txt >out.txt 
+0

你的「易」正則表達式可能不會做你所期望的:它可能發現開始的區域* first *開始註釋並以* third * end註釋結束。 – ams 2012-07-27 15:35:21

+0

有什麼建設性的說法?也許告訴我爲什麼這可能不會做我認爲的? – 2012-07-27 15:46:43

+0

我的確有一個解決方案,但解決了我自己的問題。 ;)原因是正則表達式和區域都是*貪婪*:它們總是匹配儘可能長的*模式,即使這意味着要跳過'結束'模式才能到達那裏。 – ams 2012-07-30 07:57:10

回答

1

用Perl ,它相對簡單。

perl -0777pe 's/<!--BEGIN-->\n(?:(?!<!--END-->\n).)*?\[this\].*?\n<!--END-->\n/[new content]\n/s' in.txt 

被Perl提供的好處是:(a)所述-0777「嘟嘟地喝模式」,其拉動整個輸入文件一氣呵成,代替sed的線在一次一個的處理; (b)允許點匹配換行符的/s正則表達式標誌; (c)吝嗇的重複操作員*?和朋友,這會導致重複儘可能少地匹配而不是儘可能地;最後(d)負向預測(?!...),它允許您在負向預測表達式匹配的地方禁止匹配。 (如果沒有這個,如果在「stuff before」文本中有一個「假」起始分隔符,那麼即使小氣的匹配也會匹配一個結束分隔符。)......當然,(e)一個通用編程語言sed僅適用於相對簡單的文本處理任務。

(我用簡單的開始和結束的分隔符我希望「奇怪」是故意拼寫錯誤。)

-1

你可以用sed像這樣做:

parse.sed這樣

/BEGIN/ {    # If we encounter BEGIN 
    :a     # Read all until END 
    N      # into pattern space 
    /END/!ba    #/
    /\[this\]/d   # If the block contains [this], delete it 
    s/^/[new content]\n/ # Insert [new content] before the block 
} 

運行:

sed -f parse.sed infile 

輸出:

[stuff before] 
[new content] 
<!--WIERD_SPECIAL_COMMENT_BEGIN--> 
    [not this] 
<!--WIERD_SPECIAL_COMMENT_END--> 
[stuff after] 
+0

對不起,試過了。僅刪除該行上的[this]。還試過/.*\[this\].*/d同樣的事情。似乎正在執行的範圍內的每個單獨的行的正則表達式刪除 – 2012-07-27 15:56:28

+0

@MichaelAllen:我更新了一個有效的代碼示例 – Thor 2017-06-14 20:37:45

0

聲明:我是初學者。這當然不是最好的辦法。


我在三個步驟中做了類似的事情。假設你在Linux上運行,你可以做到以下幾點:

cat originalText.txt | tr '\n' '~' > temp 

2)使用自己喜歡的方法來執行你的正則表達式:

1)以特殊字符替換換行符的所有出現在你的文件(我用perl)將特殊字符的一個實例放在你希望換行的每個位置上。確保保持特殊的換行符不變。

3)做的第一命令的其他方式解決這個時間:

cat temp | tr '~' '\n' > modText.txt 

我希望這有助於。

+0

一個選項,但可能會失敗。正在處理的文件是生成的文件。很可能我選擇的字符在最後會被替換爲\ n,當它們不應該是 – 2012-07-27 15:58:15

+0

嗯......用外來字符作爲替代品怎麼樣?我的意思是ascii有很多不太可能出現在生成文件中的替代字符。 (當然,除非有二進制部分)編輯:我用不可見的字符(如'/ 30')試過,我沒有遇到任何丟失錯誤。編輯2:正則表達式支持不可打印的字符,特別是使用\ cA到\ cZ的ascii控制字符。也許試試這些。 – 2012-07-27 16:03:17

+0

看看http://www.regular-expressions.info/characters.html#nonprint – 2012-07-27 16:08:40

0

有沒有辦法將一個範圍內的所有行添加到模式緩衝區,以便我可以一次對所有行進行regex?

當然,使用保持空間。例如:

sed -n '/begin/,/end/{ /begin/{h;d};H}; /end/{g;s/\n/<newline>/gp}' 

將取代換行符匹配 '開始' 和 '結束' 與文本<newline>

0

這可能會爲你工作線之間(GNU SED):

sed ':a;$!N;/^<!--WIERD_SPECIAL_COMMENT_BEGIN-->/!{P;D};/<!--WIERD_SPECIAL_COMMENT_END-->$/!ba;s/\[this\]/[new content]/;p;d' file