如何用 sed 递归替换字符?

如何用 sed 递归替换字符?

是否可以以递归方式替换字符序列的出现,而无需再次迭代相同的序列?

通过执行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

相关内容