我已经尝试了很长时间来替换:
(a (b ((c) (d)) (e) :hello ((f (g) h)))))
由
(a (b ((c) (d)) (e)))
hello
不会出现在字符串中的其他任何位置。如果尝试了很多不同的东西但认为它应该像这样工作:
sed -i 's/\s:hello\s.*))//g'
但是,它似乎与前两个括号不匹配,即
(a (b ((c) (d)) (e) :hello ((f (g) h ))))
但是最后两个
(a (b ((c) (d)) (e) :hello ((f (g) h)))))
从而删除 :hello
之后的所有内容。
我也尝试过使用 [^)]*
但只能让它接受一个括号而不是两个括号,并且由于 g
之后有一个右括号,所以它停止了那里。
最佳答案
.*
表示“尽可能跳过”。如果您不是这个意思,请不要使用它。
正如您已经发现的,“不是右括号”的正则表达式是 [^)]
。但是,您希望允许使用一个括号,只要它后面不紧跟着另一个括号即可。这有点难看,因为您需要 \(...\|...\)
围绕替代方案。 (切换到 sed -r 或 sed -E 并不会真正改善这种情况,因为虽然您可以避免此构造中的反斜杠,但您必须反斜杠或以其他方式转义字符类之外的文字括号。)
sed 's/\s:hello\s\([^)]\|)[^)]\)*))//g'
-i
选项在这里没有意义(如果您实际上有一个文件要处理并且您想就地处理它,也许可以将其放回去)和 \s
不可移植(切换到 [[:space:]]
以获得 POSIX 等效项)。
正如另一个答案中所指出的,更现代的正则表达式工具提供非贪婪量词,它们会尽可能少地跳过。考虑阐明一个精确的要求仍然是件好事;非贪婪匹配只是又一种实现精确的工具。太多的初学者感到困惑,并将其用作“按我的意思做”的锤子,当然它根本不是。
关于regex - 匹配第一个双括号而不是最后一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69784088/