Як рекурсивно замінити символи на 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' : Перейти до мітки "цикл", якщо попередня заміна була успішною

10

У цьому конкретному випадку корисним буде огляд вперед чи огляд. Я думаю, GNU sedце не підтримує. З perl:

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

Ви також можете використовувати lookbehind та lookahead, як:

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

Де:

(?<=X)це позитивний погляд позаду, твердження нульової довжини, що переконайтеся, що ми маємо X перед поточною позицією
(?=X)- це позитивний lookahead, твердження нульової довжини, яке гарантує, що у нас є 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на .. Перегляньте редагування.
Цифрова травма

Не рівнозначно випадку, яке надав ОП. Він дав точні відповіді, які йому потрібні (змінити випадки 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.