使用sed更改找到的模式中的任意数量的分隔符

我想用 sed更改每个.to @.@ ,但前提.是 用数字括起来。
例如:

This sentence ends with a dot. 1.2.3
Dot. 1.2.3.4.5 Dot.

目标:

This sentence ends with a dot. 1 @.@ 2 @.@ 3
Dot. 1 @.@ 2 @.@ 3 @.@ 4 @.@ 5 Dot.

该模式可以包含任意数量的整数。

我试过:

sed -E 's/([0-9]+).([0-9]+)/1 @.@ 2/g'

但它只适用于模式中的前两个数字。

回答

对于重复模式(数字-点-数字-点-数字...),替换不起作用,因为点后面的数字被“消耗”,因此引擎沿字符串移动,所以它看到的下一个字符是一个点,而不是所需的 num-dot-num 模式。

一种解决方案是使用lookarounds , 这是“零宽度”断言,因此引擎不会消耗匹配并且不会移动,但它只是从字符之间的“点”“看”来断言模式(前面或后面)匹配,可以这么说

s/ (?<=[0-9]) . (?=[0-9]) / @.@ /gx;

对于可测试的示例(在 Perl 中,已标记)

perl -wE'$_=q(Dot. 1.2.3.4.5 Dot.); say; s/(?<=[0-9]).(?=[0-9])/ @.@ /g; say'

哪个打印

点。1.2.3.4.5 点。
点。1 @.@ 2 @.@ 3 @.@ 4 @.@ 5 点。

但是lookbehind 不适用于由多于一位数字组成的“数字”,因为那时我们需要[0-9]+具有可变和无限长度的,而lookbehinds 不能(还)这样做。

如果您的情况确实可能有多位数字,那么.需要捕获之前的数字——这仍然适用于点之前的数字——然后放回去

s/([0-9]+).(?=[0-9])/$1 @.@ /g;

当然,这无论如何都可以完成,即使它总是个位数;我最初使用后视只是为了与另一侧的对称(需要先行)


在支持它们的工具中,在我的理解sed中并非如此。(感谢评论potongEd Morton通知)我仍然提供这个解决方案,因为 Perl 是标记语言之一。


回答

至于第一行,正则表达式匹配1.2第一次试验。下一个模式匹配.从前一个匹配之后的字符开始,然后失败。
随着sed请尝试:

sed -E '
:l
s/([[:digit:]]).([[:digit:]])/1 @.@ 2/
t l
' file

它从字符串的开头迭代模式匹配。

当您添加perl标签时,这里有一个替代方案perl

perl -pe 's/(?<=d).(?=d)/ @.@ /g' file


回答

使用您显示的样本,请尝试以下操作。用 GNU 编写和测试awk

awk -v RS='([0-9]+.)+[0-9]+' '{gsub(/./," @.@ ",RT);ORS=RT;print}' Input_file

说明:简单地将记录分隔符作为数字(一次或多次出现)加上点(.)的一次或多次出现,然后是 1 次或多次出现。然后@.@根据OP的要求替换最后出现的点,然后重置ORS并打印该行。要获得更多信息,awk您也可以查看man awk页面。


以上是使用sed更改找到的模式中的任意数量的分隔符的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>