反转 sed/正则表达式的模式匹配优先级顺序

反转 sed/正则表达式的模式匹配优先级顺序

考虑这个命令:

echo "string.with.dots" | sed 's/\(.*\)\.\(.*\)/\1\n\2/'

(将直到最后一个字符的任意字符匹配到第一个捕获组,.并将其后的任何字符匹配到第二个捕获组。)

输出:

string.with
dots

合理地(我认为)我认为使用正确组合的锚点可以扭转这种行为(即匹配将string针对第一个捕获组和with.dots第二个捕获组),但是:

echo "string.with.dots" | sed 's/^\(.*\)\.\(.*\)/\1\n\2/'
echo "string.with.dots" | sed 's/^\(.*\)\.\(.*\)$/\1\n\2/'
echo "string.with.dots" | sed 's/\(.*\)\.\(.*\)$/\1\n\2/'

全部输出:

string.with
dots

我不知道模式匹配是如何实现的,但似乎它总是优先考虑更靠近字符串开头的模式,而不是更靠近字符串结尾的模式(尽管存在^或缺失$)。

怎么能这种行为如果可能的话,进行更改(即,不是如何为这个例子编写一个硬编码的解决方案,而是如何将模式匹配的优先级顺序反转为sed或反转为正则表达式)?

答案1

添加两个rev并交换\1\2

echo "string.with.dots" | rev | sed 's/\(.*\)\.\(.*\)/\2\n\1/' | rev

输出:

细绳
带点

答案2

为了得到你想要的,尝试这个:

sed -r 's/^([^.]*)\.(.*)/\1\n\2/'

测试:

$ echo "string.with.dots" | sed -r 's/^([^.]*)\.(.*)/\1\n\2/'
string
with.dots

sed将会贪婪地匹配,因此当您使用sed 's/\(.*\)\.\(.*\)/\1\n\2/'它时,它将贪婪地匹配到最后一个.作为第一个捕获的组,然后将其余的.作为第二个。

在我的sed表达中,为了避免sed贪婪,我必须寻找一些替代方案。我从头到尾匹配 a.作为第一组 ( [^.]*),然后将第一组匹配之后的任何内容作为第二组。

现在,如果您希望所有部分都放在.单独的行中:

$ echo "string.with.dots" | sed -r 's/^([^.]*)\.([^.]*)\.(.*)/\1\n\2\n\3/'
string
with
dots

答案3

我想知道你是否可以使用 bash参数扩展

$ s="string.with.dots"
$ echo "${s%%.*}"; echo "${s#*.}"
string
with.dots
$ echo "${s%.*}"; echo "${s##*.}"
string.with
dots

相关内容