如何匹配起始分隔符和结束分隔符,使文本不包含结束分隔符(即非贪婪匹配)?

时间:2016-07-03 12:44:15

标签: regex shell posix

在POSIX shell脚本中,我需要找到{{}}中包含的所有文本,并用星号替换文本和周围的大括号。

例如,如果输入是

{{ abc }} def {{ ghi {jkl} mno }} pqr

然后输出必须

* def * pqr

我无法为此提出sed命令。

我尝试了几个命令,但他们没有工作。例如,以下命令不会产生所需的输出,因为sed执行贪婪匹配。最终匹配{{ abc }} def {{ ghi {jkl} mno }}作为第一个匹配,而不仅仅是{{ abc }}

$ echo "{{ abc }} def {{ ghi {jkl} mno }} pqr" | sed 's/{{.*}}/*/g'
* pqr

这是另一个不起作用的例子,因为它最终匹配得太少。它与{{ ghi {jkl} mno }}(我们想要匹配)不匹配,因为字符串的这一部分包含}

$ echo "{{ abc }} def {{ ghi {jkl} mno }} pqr" | sed 's/{{[^}]*}}/*/g'
* def {{ ghi {jkl} mno }} pqr

我怎么能做这样的比赛?

我已经完成Non greedy regex matching in sed?但是那里的解决方案没有帮助,因为我想要匹配{{}}之间的所有内容,除了两个连续字符的特定序列,即}}。如果我尝试匹配除了单个字符之外的分隔符之间的所有内容,那么该问题的答案就会有所帮助。

1 个答案:

答案 0 :(得分:0)

如果您的正则表达式与不包含"}}"的内容相匹配,那么您可以将其用作"{{" exp "}}"。遗憾的是sed没有补充regexp运算符。许多正则表达式实现都有,因为常规语言的补充是常规的。所以我们知道它存在,但我们只需要手动构建它。

以比sed更易读的格式,接近的是"{{" ( [^}]* ( "}" [^}] )? )* "}}"

正确sed即:

$ echo "{{ abc }} def {{ ghi {jkl} mno }} pqr" \
    | sed 's/{{\([^}]*\(}[^}]\)\?\)*}}/*/g'
* def * pqr
$

这可能不是您想要的,具体取决于您是否预期连续使用三个括号。这个abc {{ def { ghi }}}会发生什么?如果你真的需要平衡大括号,那么它就会把它从常规语言领域转移到需要更强大工具的无上下文语言中。

根据您的用户名,您可能希望阅读有关正式语言和自动机理论的书籍。它可能是" old"技术,但它是非常强大的,并且通过各种技术全天使用。