regex - 匹配第一个双括号而不是最后一个

标签 regex sed

我已经尝试了很长时间来替换:

(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/

相关文章:

javascript - 正则表达式(只有 1 点)

Linux - 操作两个文本文件的列

sed - 删除包含两个点的行,点之间有字符

shell - 选择一个模式可能出现两次的标记模式之间的线

java - 使用正则表达式进行拆分,无法正确返回数字

python - 正则表达式从字符串中过滤版本

bash - 如何根据具有给定值的字段数过滤制表符分隔的输入?

linux - 按特定分隔符删除字符串

regex - Sed 通配符——替换某些字符的中间

javascript - 涉及转义符号的正则表达式