2012-01-29 46 views
17

找到一個子字符串(一個字符串前後是特定字符串)的正確語法是什麼不是匹配特定模式?sed正則表達式和子字符串否定

例如,我想利用其與開始BEGIN_所有子,_END和是等於FOO之間的子串;並用格式「(內部子字符串)」替換整個子字符串。下面將匹配:

  • BEGIN_bar_END - >(bar)
  • BEGIN_buz_END - >(buz)
  • BEGIN_ihfd8f398IHFf9f39_END - >(ihfd8f398IHFf9f39)

BEGIN_FOO_END將不匹配。

我已經打得四處以下,但似乎無法找到正確的語法:

sed -e 's/BEGIN_(^FOO)_END/($1)/g' 
sed -e 's/BEGIN_([^FOO])_END/($1)/g' 
sed -e 's/BEGIN_(?!FOO)_END/($1)/g' 
sed -e 's/BEGIN_(!FOO)_END/($1)/g' 
sed -e 's/BEGIN_(FOO)!_END/($1)/g' 
sed -e 's/BEGIN_!(FOO)_END/($1)/g' 
+0

作爲一個說明,與全行打交道時,這可以使用''實現!http://www.grymoire.com/Unix/Sed.html#uh-32 – Zenexer 2013-05-23 02:52:13

回答

27

有一個在桑達,IIRC沒有一般否定運算符,因爲與否定到DFA的正則表達式的編譯過程會花費指數時間。您可以解決這跟

'/BEGIN_FOO_END/b; s/BEGIN_\(.*\)_END/(\1)/g' 

其中/BEGIN_FOO_END/b的意思是:如果我們發現BEGIN_FOO_END,然後分支(跳躍)到sed腳本結束。

+9

也可以寫成'sed'/ BEGIN_FOO_END /!s/BEGIN _ \(。* \)_ END /(\ 1)/ g'' – potong 2012-01-29 15:41:21

+2

我想指出'sed'/ BEGIN_FOO_END /!s | BEGIN_ \ (。* \)_ END |(\ 1)| g''可以運行但是'sed'| BEGIN_FOO_END |!s | BEGIN _ \(。* \)_ END |(\ 1)| g''不會!顯然,它可以讓你在後面的部分替換不同於「/」的分隔符,而不是在第一部分。奇怪的。 – CommaToast 2014-09-05 20:56:50

+1

@CommaToast的///命令可以使用任意的分隔符;地址不能。 – TheDudeAbides 2015-06-13 00:58:05

2

我不知道的一個漂亮的方式,但你總是可以做到這一點:

$ cat file 
BEGIN_FOO_END 
BEGIN_FrOO_END 
BEGIN_rFOO_END 
$ sed '/BEGIN_FOO_END/ !{s/BEGIN_\([^_]*\)_END/(\1)/}' file 
BEGIN_FOO_END 
(FrOO) 
(rFOO) 
3

這可能會爲你工作:

sed 'h;s/BEGIN_\(.*\)_END/(\1)/;/^(FOO)$/g' file 

這隻能如果只有一個字符串每行。

對於每行多個字符串:

sed 's/BEGIN_\([^F][^_]*\|F[^O][^_]*\|FO[^O][^_]*\|FOO[^_]\+\)_END/\(\1\)/g' file 

還是比較容易理解:

sed 's/\(BEGIN_\)FOO\(_END\)/\1\n\2/g;s/BEGIN_\([^\n_]*\)_END/(\1\)/g;s/\n/FOO/g' file