使用 sed 更改找到的模式中的任意数量的分隔符
Change any number of delimiters in found pattern with sed
我想用 sed 将每个 .
更改为 @.@
,但前提是 .
包含在数字中。
例如:
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]+)/ @\.@ /g'
但它只适用于模式中的前两个数字。
使用您显示的示例,请尝试执行以下操作。在 GNU awk
.
中编写和测试
awk -v RS='([0-9]+.)+[0-9]+' '{gsub(/\./," @.@ ",RT);ORS=RT;print}' Input_file
解释: 只需将记录分隔符作为数字(一次或多次出现)和点(.)的一次或多次出现后跟 1 个或多个数字出现。然后根据 OP 的要求用 @.@
替换最后出现的点,然后重置 ORS 并打印该行。要获得有关 awk
的更多信息,您也可以查看 man awk
页面。
对于重复模式(数字-点-数字-点-数字...)替换不起作用,因为点后面的数字是
“consumed”,所以引擎沿着字符串移动,所以它看到的下一个字符是一个点,而不是所需的 num-dot-num 模式。
一种解决方案是使用 lookarounds、†,它们是“零宽度”断言,因此引擎不会消耗匹配项并且不会t 继续前进,但它只是从字符之间的“点”“看”来断言模式(前面或后面)匹配,可以说
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'
打印
Dot. 1.2.3.4.5 Dot.
Dot. 1 @.@ 2 @.@ 3 @.@ 4 @.@ 5 Dot.
但是lookbehind 不适用于由一个以上数字组成的“number”,从那时起我们需要 [0-9]+
,它具有变量和无限长度,whiat lookbehinds 不能(还)做。
如果在您的情况下确实可能有多位数字,那么需要捕获 .
之前的数字——这仍然适用于 before[=42] =] 点 -- 然后放回去
s/([0-9]+)\.(?=[0-9])/ @.@ /g;
当然,这无论如何都可以做到,即使它总是个位数;我最初使用 lookbehind 只是为了与另一边对称(需要 lookahead)
† 在支持它们的工具中,据我所知 sed
不是。 (感谢 potong
和 Ed Morton
的评论告知)我仍然提供这个解决方案,因为 Perl 是标记语言之一。
至于第一行,正则表达式匹配 1.2
进行第一次试验。
下一个模式匹配以字符 .
开始,紧跟在
上一场比赛失败了。
使用 sed
请尝试:
sed -E '
:l
s/([[:digit:]])\.([[:digit:]])/ @.@ /
t l
' file
从字符串的开头迭代模式匹配。
当您在标签中添加 perl
时,这里有一个替代方法 perl
:
perl -pe 's/(?<=\d)\.(?=\d)/ @.@ /g' file
这是一个 POSIX awk 解决方案:
awk '{while (match([=10=], /[0-9]\.[0-9]/))
[=10=] = substr([=10=], 1, RSTART) " @.@ " substr([=10=], RSTART+2)} 1' file
This sentence ends with a dot. 1 @.@ 2 @.@ 3
Dot. 1 @.@ 2 @.@ 3 @.@ 4 @.@ 5 Dot.
在每个 Unix 机器上的任何 shell 中使用任何 sed:
$ sed 's/\([0-9]\)\.\([0-9]\)/ @.@ /g; s/\([0-9]\)\.\([0-9]\)/ @.@ /g' file
This sentence ends with a dot. 1 @.@ 2 @.@ 3
Dot. 1 @.@ 2 @.@ 3 @.@ 4 @.@ 5 Dot.
您需要输入 2 次,因为 1.2.3
的给定输入只有 1.2
会与 [0-9]\.[0-9]
的第一遍匹配,2.3
不会在那次通过中被识别,因为 2
已经被第一场比赛消耗掉了,所以在第一场比赛中剩下的输入是 .3
,你需要第二次通过(现在反对 1 @.@ 2.3
) 匹配 2.3
.
我想用 sed 将每个 .
更改为 @.@
,但前提是 .
包含在数字中。
例如:
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]+)/ @\.@ /g'
但它只适用于模式中的前两个数字。
使用您显示的示例,请尝试执行以下操作。在 GNU awk
.
awk -v RS='([0-9]+.)+[0-9]+' '{gsub(/\./," @.@ ",RT);ORS=RT;print}' Input_file
解释: 只需将记录分隔符作为数字(一次或多次出现)和点(.)的一次或多次出现后跟 1 个或多个数字出现。然后根据 OP 的要求用 @.@
替换最后出现的点,然后重置 ORS 并打印该行。要获得有关 awk
的更多信息,您也可以查看 man awk
页面。
对于重复模式(数字-点-数字-点-数字...)替换不起作用,因为点后面的数字是 “consumed”,所以引擎沿着字符串移动,所以它看到的下一个字符是一个点,而不是所需的 num-dot-num 模式。
一种解决方案是使用 lookarounds、†,它们是“零宽度”断言,因此引擎不会消耗匹配项并且不会t 继续前进,但它只是从字符之间的“点”“看”来断言模式(前面或后面)匹配,可以说
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'
打印
Dot. 1.2.3.4.5 Dot. Dot. 1 @.@ 2 @.@ 3 @.@ 4 @.@ 5 Dot.
但是lookbehind 不适用于由一个以上数字组成的“number”,从那时起我们需要 [0-9]+
,它具有变量和无限长度,whiat lookbehinds 不能(还)做。
如果在您的情况下确实可能有多位数字,那么需要捕获 .
之前的数字——这仍然适用于 before[=42] =] 点 -- 然后放回去
s/([0-9]+)\.(?=[0-9])/ @.@ /g;
当然,这无论如何都可以做到,即使它总是个位数;我最初使用 lookbehind 只是为了与另一边对称(需要 lookahead)
† 在支持它们的工具中,据我所知 sed
不是。 (感谢 potong
和 Ed Morton
的评论告知)我仍然提供这个解决方案,因为 Perl 是标记语言之一。
至于第一行,正则表达式匹配 1.2
进行第一次试验。
下一个模式匹配以字符 .
开始,紧跟在
上一场比赛失败了。
使用 sed
请尝试:
sed -E '
:l
s/([[:digit:]])\.([[:digit:]])/ @.@ /
t l
' file
从字符串的开头迭代模式匹配。
当您在标签中添加 perl
时,这里有一个替代方法 perl
:
perl -pe 's/(?<=\d)\.(?=\d)/ @.@ /g' file
这是一个 POSIX awk 解决方案:
awk '{while (match([=10=], /[0-9]\.[0-9]/))
[=10=] = substr([=10=], 1, RSTART) " @.@ " substr([=10=], RSTART+2)} 1' file
This sentence ends with a dot. 1 @.@ 2 @.@ 3
Dot. 1 @.@ 2 @.@ 3 @.@ 4 @.@ 5 Dot.
在每个 Unix 机器上的任何 shell 中使用任何 sed:
$ sed 's/\([0-9]\)\.\([0-9]\)/ @.@ /g; s/\([0-9]\)\.\([0-9]\)/ @.@ /g' file
This sentence ends with a dot. 1 @.@ 2 @.@ 3
Dot. 1 @.@ 2 @.@ 3 @.@ 4 @.@ 5 Dot.
您需要输入 2 次,因为 1.2.3
的给定输入只有 1.2
会与 [0-9]\.[0-9]
的第一遍匹配,2.3
不会在那次通过中被识别,因为 2
已经被第一场比赛消耗掉了,所以在第一场比赛中剩下的输入是 .3
,你需要第二次通过(现在反对 1 @.@ 2.3
) 匹配 2.3
.