Как рекурсивно заменить символы на sed?


13

Можно ли рекурсивно заменить вхождения последовательности символов без повторения итерации по той же самой последовательности?

Выполняя 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?

Ответы:


24

Ты можешь сделать:

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

С:

  • -e ':loop' : Создать ярлык "петли"
  • -e 't loop' : Переход к метке «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на .. Пожалуйста, смотрите редактировать.
— Цифровая травма

Не соответствует случаю, который выдал ОП. Он дал именно те 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.