如何用sed递归替换字符?


13

是否可以递归地替换出现的字符序列,而无需再次遍历同一序列?

通过sed在以下情况下执行a ,我可以获得上述输出。

$ 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是否有可能达到预期的行为?

Answers:


24

你可以做:

> echo XXXX | sed -e ':loop' -e 's/XX/XoX/g' -e 't loop'
XoXoXoX

带有:

  • -e ':loop' :创建一个“循环”标签
  • -e 't loop' :如果先前的替换成功,则跳转到“循环”标签

10

在这种特殊情况下,向前或向后看将很有用。我认为GNU sed不支持这些。与perl

perl -ne 's/X(?=X)/Xo/g; print;'

您还可以像这样使用lookbehind和lookahead

s/(?<=X)(?=X)/o/g

哪里:

(?<=X)是正向后看,零长度断言确保我们在当前位置之前有一个X
(?=X)是正向超前,零长度断言确保我们在当前位置之前有一个X

在perl一线式中使用:

perl -pe 's/(?<=X)(?=X)/o/g' inputfile

哪里:

-p 使Perl假定在程序周围循环,并隐含显示当前行


5

循环回答是完成您要问的一般方法。

但是,就您的数据而言,假设您使用的是GNU,则可以简单地执行以下操作:

sed 's/\B/o/g'

\b\B选项的正则表达式的扩展

  • \b 匹配单词边界,即从“单词”字符到“非单词”字符的转换,反之亦然
  • \B与相对\b。即差距“内”字。这使我们可以根据需要在一个单词的内部而不是外部插入字符。

在线尝试

这假定输入字符实际上是所有“单词”字符。


或者,如果您没有GNU sed,或者输入的字符也不都是“单词”字符,那么您仍然可以实现目标而无需循环:

sed 's/./&o/g;s/o$//'

这只是o在每个字符后放置一个,然后o从字符串中删除最后一个。

在线尝试


1
假设输入字符串由一定数量的组成,X并且没有其他内容。如果还有其他字符,则两种解决方案都将失败...
AnoE

@AnoE在第二个示例中,通过简单替换为X来解决此问题.。请参阅编辑。
Digital Trauma

与OP给出的情况不同。他给出了所需的确切RE(更改字符串中XX的出现)。对于给定的完全相同的输入字符串,您的版本只给出与他相同的结果。不适用于通用输入字符串。
AnoE

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.