Ты можешь сделать:
> echo XXXX | sed -e ':loop' -e 's/XX/XoX/g' -e 't loop' XoXoXoX
С:
-e ':loop'
: Создать ярлык «петля»-e 't loop'
: Переход к метке «loop», если предыдущая замена прошла успешно
Можно ли заменить вхождения последовательности символов рекурсивно, не повторяя ту же последовательность снова?
Выполняя 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?
Ты можешь сделать:
> echo XXXX | sed -e ':loop' -e 's/XX/XoX/g' -e 't loop' XoXoXoX
С:
-e ':loop'
: Создать ярлык «петля»-e 't loop'
: Переход к метке «loop», если предыдущая замена прошла успешноВ этом конкретном случае было бы полезно забегать вперед или оглядываться назад. Я думаю, что 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 предполагать цикл вокруг программы с неявным выводом текущей строки
Циклический ответ - это общий способ сделать то, что вы просите.
Однако в случае ваших данных, если вы используете GNU, вы можете просто сделать:
sed 's/\B/o/g'
\b
И \B
варианты регулярных выражений расширений :
\b
соответствует границам слов, то есть переходу от символа «слово» к символу «не слово», или наоборот\B
соответствует противоположности \b
. то есть пробелы "внутри" слова. Это позволяет нам вставлять символы внутри слова, но не снаружи, как требуется.Это предполагает, что входные символы на самом деле являются символами «слова».
В качестве альтернативы, если у вас нет GNU sed или если входные символы не все «слово», вы все равно можете достичь своей цели без зацикливания:
sed 's/./&o/g;s/o$//'
Это просто помещает o
после каждого символа, а затем удаляет финал o
из строки.
Я проверил, есть ли какой-нибудь флаг, чтобы это произошло.
Даже если бы такое поведение было там, оно будет очень ресурсоемким.
Однако в этом конкретном случае использования можно получить выражение всего два раза и достичь требуемой функциональности. т.е. с 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