是否可以以递归方式替换字符序列的出现,而无需再次迭代相同的序列?
通过执行sed
以下场景中所述的操作,我可以获得所提到的输出。
$ echo XX | sed -e 's/XX/XoX/g'
XoX
$ echo XXX | sed -e 's/XX/XoX/g'
XoXX
$ echo XXXX | sed -e 's/XX/XoX/g'
XoXXoX
不过,我期望输出遵循以下行为。
输入:
XX
XXX
XXXX
预期输出:
XoX
XoXoX
XoXoXoX
仅使用 sed 是否可以实现预期的行为?
答案1
你可以做:
> echo XXXX | sed -e ':loop' -e 's/XX/XoX/g' -e 't loop'
XoXoXoX
和:
-e ':loop'
:创建“循环”标签-e 't loop'
:如果先前的替换成功,则跳转到“循环”标签
答案2
在这个特定情况下,前瞻或后瞻会很有用。我认为 GNUsed
不支持这些。使用perl
:
perl -ne 's/X(?=X)/Xo/g; print;'
您还可以使用后视和前视喜欢:
s/(?<=X)(?=X)/o/g
在哪里:
(?<=X)
是一个正向后视,一个零长度的断言,确保在当前位置之前有一个 X
(?=X)
是一个正向前视,一个零长度的断言,确保在当前位置之后有一个 X
在 perl 单行语句中使用:
perl -pe 's/(?<=X)(?=X)/o/g' inputfile
在哪里:
-p
导致 Perl 假设程序循环并隐式打印当前行
答案3
循环答案是完成您所问问题的一般方法。
但是,对于您的数据,假设您使用 GNU,您可以简单地执行以下操作:
sed 's/\B/o/g'
和\b
选项\B
包括正则表达式扩展:
\b
匹配单词边界,即从“单词”字符到“非单词”字符的转换,或反之亦然\B
与 匹配\b
。即匹配单词“内部”的间隙。这允许我们在单词内部插入字符,但不能在单词外部插入字符,这是必需的。
在线尝试。
这假设输入的字符实际上都是“单词”字符。
或者,如果您没有 GNU sed,或者输入的字符并非全部是“单词”字符,您仍然可以不使用循环来实现您的目标:
sed 's/./&o/g;s/o$//'
这只是o
在每个字符后放置一个,然后o
从字符串中删除最后一个字符。
在线尝试。
答案4
我检查了是否有任何标志可以实现这一点。
即使存在这种行为,也会非常耗费资源。
然而,在这种特殊的用例中,只需使用两次表达式就可能实现所需的功能。即使用 2 个重复sed
表达式。
echo XX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g' # outputs XoX
echo XXX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g' # outputs XoXoX
echo XXXX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g' # outputs XoXoXoX