2010-12-21 145 views
2

我想通了,爲了把[一些名稱]到[some_name]我需要使用下面的表達式:如何使用sed用下劃線替換方括號內的所有空格?

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

即創建一個反向引用捕獲的任何一個文字「[」包含啓動任何數量的非空格字符,後跟一個空格,用非空格字符替換後跟下劃線。但我還不知道如何改變這個表達式,所以它適用於大括號內的所有下劃線,例如[幾個字]轉換成[a_few_words]。

我感覺到我很接近,但我只是錯過了一大堆知識,可以解鎖使這件事情在包含在一行中的第一組限制內無限次地工作的關鍵(在這種情況下爲SQL Server DDL)。

感激地收到任何建議....

回答

3

有兩個部分所需要的詭計:當你達到一個接近括號(但這樣做反覆上線)

  1. 停止更換:

    s/\(\[[^] ]*\) /\1_/g 
    

    此相匹配的開括號,後面的零個或多個字符既不是一個空白,也不是接近方形支架。全局後綴意味着該模式適用於所有以開放方括號開始的序列,最後是行上的空白或近方括號。還要注意,這個正則表達式不會改變'[single-word] and context',而原始文件會將其轉換爲'[single-word]_and context',這不是練習的目標。

  2. 讓sed從這個地方開始重複搜索。不幸的是,沒有一個真正的好方法來做到這一點。 Sed總是在被取代的文本之後繼續搜索;這是我們不想要的一次。有時候,您可以簡單地重複替代操作。在這種情況下,每次替換成功時都必須重複它,當沒有替換時停止。

sed不爲人知的操作中的兩個是「:label」和「t」命令。不過,它們出現在Unix的第七版(大約1978年)中,所以它們不是新功能。首先簡單地識別腳本中的一個位置,這可以用「b」(這裏未想)或「t‘被跳樓:到’:」功能的軸承,如果任何替換標籤

[2addr]t [label] 

分公司自從最近讀取輸入行或執行't'函數以來已經做出。如果沒有指定標籤,則分支到腳本的末尾。

奇妙:我們需要:

sed -e ':redo; s/\(\[[^] ]*\) /\1_/g; t redo' data.file 

- 它不工作,都在這樣的一條線(至少不是在MacOS X)。這也令人欽佩的工作,雖然:

sed -e ':redo 
     s/\(\[[^] ]*\) /\1_/g 
     t redo' data.file 

或者,正如在評論中指出,你可以寫三個獨立的 '-e' 選項(在MacOS X的工作原理):

sed -e ':redo' -e 's/\(\[[^] ]*\) /\1_/g' -e 't redo' data.file 

鑑於數據文件:

a line with [one blank] word inside square brackets. 
a line with [two blank] or [three blank] words inside square brackets. 
a line with [no-blank] word inside square brackets. 
a line with [multiple words in a single bracket] inside square brackets. 
a line with [multiple words in a single bracket] [several times on one line] 

從所示的sed腳本輸出爲:

a line with [one_blank] word inside square brackets. 
a line with [two_blank] or [three_blank] words inside square brackets. 
a line with [no-blank] word inside square brackets. 
a line with [multiple_words_in_a_single_bracket] inside square brackets. 
a line with [multiple_words_in_a_single_bracket] [several_times_on_one_line] 

最後,如果你只需要在每一行的第一個方括號字段中完成這個問題,那麼我們需要確保在開始匹配之前沒有空的方括號。這種變體的工作原理:

sed -e ':redo' -e 's/^\([^]]*\[[^] ]*\) /\1_/' -e 't redo' data.file 

(在「G」限定符不見了 - 它可能不需要在其他變體要麼給出的循環;它的存在可能使過程稍微更有效,但它很可能會基本上不可能檢測到該圖案現在錨定到該行的開頭(脫字符)並且包含零個或多個在第一個開放方括號之前未打開方括號的字符)。

Sample output:

a line with [two_blank] or [three blank] words inside square brackets. 
a line with [no-blank] word inside square brackets. 
a line with [multiple_words_in_a_single_bracket] inside square brackets. 
a line with [multiple_words_in_a_single_bracket] [several times on one line] 
+0

啊,聰明地觀察到`[a b c]`在第一個子之後變成`[a_b c]`,因此可以遞歸處理。我正在考慮將'[stuff]`分成一個單獨的行,'這些行,然後重新加入。 – 2010-12-21 21:43:17

+0

+1。它是否在OS X上執行此操作:'sed -e':redo'-e's/\(\ [[^]] * \)/ \ 1_/g'-e't redo'`而不是打破它在多條線上? – 2010-12-22 02:03:25

1

This i ■在如Perl語言具有「可執行」替代簡單:

perl -wne 's/(\[.*?])/ do { my $x = $1; $x =~ y, ,_,; $x } /ge; print' 

或者更明確地分裂起來:

sub replace_with_underscores { 
    my $s = shift; 
    $s =~ y/ /_/; 
    $s 
} 
s/(\[.*?])/ replace_with_underscores($1) /ge; 

.*?是非貪婪匹配(爲了避免含糊不清在一起的兩個相鄰的括號內的短語)和e標誌替代導致它被評估,所以你可以調用一個函數來完成內部工作。

相關問題