Regex 为什么sed不';是否打印可选组?
我有两个字符串,分别是foo\u bar和foo\u abc\u bar。我想将两者匹配,如果第一个匹配,我想用=符号强调它。所以,我的猜测是:Regex 为什么sed不';是否打印可选组?,regex,string,bash,sed,regex-group,Regex,String,Bash,Sed,Regex Group,我有两个字符串,分别是foo\u bar和foo\u abc\u bar。我想将两者匹配,如果第一个匹配,我想用=符号强调它。所以,我的猜测是: echo 'foo_abc_bar' | sed -r 's/(foo).*(abc)?.*(bar)/\1=\2=\3/g' > foo==bar 或 但正如上面的输出所示,它们都不起作用 如何指定一个可选组,如果字符串包含该组,则该组将匹配,如果不包含,则跳过该组?解决方案: echo 'foo_abc_bar' | sed -r 's/(
echo 'foo_abc_bar' | sed -r 's/(foo).*(abc)?.*(bar)/\1=\2=\3/g'
> foo==bar
或
但正如上面的输出所示,它们都不起作用
如何指定一个可选组,如果字符串包含该组,则该组将匹配,如果不包含,则跳过该组?解决方案:
echo 'foo_abc_bar' | sed -r 's/(foo)_((abc)_)?(bar)/\1=\3=\4/g'
您以前的尝试失败的原因:
echo 'foo_abc_bar' | sed -r 's/(foo)_((abc)_)?(bar)/\1=\3=\4/g'
*
是贪婪的,因此对于正则表达式(foo)。*(abc)?*(bar)
尝试匹配“foo\u abc\u bar”
时,(foo)
将匹配“foo”
,然后*
将首先匹配字符串的其余部分(“u abc\u bar”
)。正则表达式将继续运行,直到到达所需的(bar)
组,这将失败,此时正则表达式将通过放弃与*
匹配的字符来回溯。直到第一个*
仅匹配“abc”
,最后一组才可以匹配“bar”
。因此,不是在捕获组中匹配字符串中的'abc'
,而是在非捕获组中匹配
我的解决方案说明:
echo 'foo_abc_bar' | sed -r 's/(foo)_((abc)_)?(bar)/\1=\3=\4/g'
首先也是最重要的一点是将*
替换为.
,如果您知道分隔符是什么,则无需匹配任何任意字符串。我们需要做的下一件事是准确地找出字符串的哪一部分是可选的。如果字符串<代码>“FuixAbcBar Bar”和(abc?)
将其放入可选组。最后一步是确保在捕获组中仍然有字符串'abc'
,我们可以通过将该部分包装到另一个组中来完成,因此我们最终得到((abc)\)
。然后我们需要调整替换,因为有一个额外的组,所以我们使用\1=\2=\3=\4
,而不是\1=\3=\4
,\2
将是字符串'abc'
(如果匹配)。请注意,在大多数regex实现中,您也可以使用非捕获组并继续使用\1=\2=\3
,但sed不支持非捕获组
另一种选择:
echo 'foo_abc_bar' | sed -r 's/(foo)_((abc)_)?(bar)/\1=\3=\4/g'
我认为上面的正则表达式是最好的选择,因为它是最显式的(它将只匹配您感兴趣的确切字符串)。但是,您也可以通过使用惰性重复(匹配尽可能少的字符)而不是贪婪重复(匹配尽可能多的字符),来避免上述问题。您可以通过将*
更改为*?
来完成此操作,因此您的表达式如下所示:
echo 'foo_abc_bar' | sed -r 's/(foo).*?(abc).*?(bar)/\1=\2=\3/g'
也许你可以简单地使用:
echo 'foo_abc_bar' | sed -r 's/(foo|bar|abc)_?/\1=/g'
echo 'foo_bar' | sed -r 's/(foo|bar|abc)_?/\1=/g'
> foo=abc=bar=
> foo=bar=
这避免了使用
foo==bar
时出现的foo==bar
,我发现在匹配前有时在匹配后使用=
来显示强调有点奇怪。为什么在表达式中使用*
,下划线可以用任意字符串替换吗?