2012-01-29 52 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