使用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中并非如此。(感谢评论potong和Ed 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页面。