Я хочу использовать sed
для замены чего-либо в строке между первым AB
и первым появлением AC
(включительно) на XXX
.
К примеру , у меня есть эта строка (эта строка только для теста):
ssABteAstACABnnACss
и я хотел бы вывод , подобный этому: ssXXXABnnACss
.
Я сделал это с perl
:
$ echo 'ssABteAstACABnnACss' | perl -pe 's/AB.*?AC/XXX/'
ssXXXABnnACss
но я хочу реализовать это с sed
. Следующее (с использованием Perl-совместимого регулярного выражения) не работает:
$ echo 'ssABteAstACABnnACss' | sed -re 's/AB.*?AC/XXX/'
ssXXXss
text-processing
sed
regular-expression
بارپابابا
источник
источник
Ответы:
Регулярные выражения Sed соответствуют самому длинному совпадению. Сед не имеет эквивалента не жадных.
Очевидно, что мы хотим сделать, это матч
AB
споследующим
AC
,сопровождаемого
AC
К сожалению,
sed
не могу сделать # 2 - по крайней мере, не для многосимвольного регулярного выражения. Конечно, для односимвольного регулярного выражения, такого как@
(или даже[123]
), мы можем сделать[^@]*
или[^123]*
. И поэтому мы можем обойти ограничения СЕПГА путем изменений всех вхожденийAC
в ,@
а затем в поискахAB
споследующим
@
,сопровождаемого
@
как это:
Последняя часть изменяет непревзойденные экземпляры
@
обратно наAC
.Но, конечно, это безрассудный подход, потому что входные данные уже могут содержать
@
символы, поэтому, сопоставляя их, мы можем получить ложные срабатывания. Однако, поскольку ни одна переменная оболочки никогда не будет содержать символ NUL (\x00
), NUL, вероятно, является хорошим символом для использования в вышеуказанном обходном пути вместо@
:Использование NUL требует GNU sed. (Чтобы убедиться, что функции GNU включены, пользователь не должен устанавливать переменную оболочки POSIXLY_CORRECT.)
Если вы используете sed с
-z
флагом GNU для обработки входных данных, разделенных NUL, таких как выходные данныеfind ... -print0
, то NUL не будет в пространстве шаблонов, и NUL является хорошим выбором для подстановки здесь.Хотя NUL не может быть в переменной bash, его можно включить в
printf
команду. Если ваша входная строка может содержать какой-либо символ, включая NUL, см. Ответ Стефана Шазеласа, в котором добавлен умный метод экранирования.источник
echo
илиprintf
`\ 000 'просто отлично в bash (или ввод может происходить из файла). Но в целом строка текста, конечно, вряд ли имеет NUL.AC
наAC@
и обратно?Некоторые
sed
реализации поддерживают это.ssed
имеет режим PCRE:AT & T ast sed имеет конъюнкцию и отрицание при использовании расширенных регулярных выражений :
В частности, вы можете использовать эту технику: заменить конечную строку (здесь
AC
) одним символом, который не встречается ни в начальной, ни в конечной строке (как:
здесь), чтобы вы могли это сделатьs/AB[^:]*://
, и в случае, если этот символ может появиться на входе используйте механизм экранирования, который не конфликтует со строками начала и конца.Пример:
В GNU
sed
подход заключается в использовании символа новой строки в качестве символа замены. Посколькуsed
обрабатывает одну строку за раз, новая строка никогда не встречается в пространстве шаблона, поэтому можно сделать следующее:Это обычно не работает с другими
sed
реализациями, потому что они не поддерживают[^\n]
. С GNUsed
вы должны убедиться, что POSIX-совместимость не включена (как с переменной окружения POSIXLY_CORRECT).источник
Нет, регулярные выражения sed не имеют жадного соответствия.
Вы можете сопоставить весь текст вплоть до первого вхождения
AC
, используя «что-либо не содержащееAC
», послеAC
которого следует то же самое, что и в Perl.*?AC
. Дело в том, что «все, что не содержитAC
» не может быть легко выражено как регулярное выражение: всегда есть регулярное выражение, которое распознает отрицание регулярного выражения, но регулярное выражение отрицания быстро усложняется. А в переносимом sed это вообще невозможно, поскольку регулярное выражение отрицания требует группировки чередования, которое присутствует в расширенных регулярных выражениях (например, в awk), но не в переносимых базовых регулярных выражениях. Некоторые версии sed, такие как GNU sed, имеют расширения для BRE, которые позволяют ему выражать все возможные регулярные выражения.Из-за сложности отрицания регулярного выражения это не обобщает хорошо. Вместо этого вы можете временно преобразовать линию. В некоторых реализациях sed вы можете использовать новые строки в качестве маркера, так как они не могут появляться в строке ввода (и если вам нужно несколько маркеров, используйте новую строку, за которой следует переменный символ).
Однако следует помнить, что обратная косая черта не работает в наборе символов с некоторыми версиями sed. В частности, это не работает в GNU sed, который является реализацией sed для не встроенного Linux; в GNU sed вы можете использовать
\n
вместо:В этом конкретном случае достаточно заменить первый
AC
символ новой строкой. Подход, который я представил выше, носит более общий характер.Более мощный подход в sed - это сохранить линию в пространстве удержания, удалить все, кроме первой «интересной» части строки, заменить пространство удержания и пространство образца или добавить пространство образца в пространство удержания и повторить. Однако, если вы начнете делать такие сложные вещи, вам стоит подумать о переходе на awk. В Awk также нет не жадного соответствия, но вы можете разбить строку и сохранить части в переменные.
источник
s/\n//g
удаляет все новые строкиsed - не жадное совпадение от Christoph Sieghart
источник
В вашем случае вы можете просто отменить закрытие char следующим образом:
источник
AB
и первое появлениеAC
сXXX
...» и дает вssABteAstACABnnACss
качестве примера входных данных. Этот ответ работает для этого примера , но не отвечает на вопрос в целом. Например,ssABteCstACABnnACss
также должен выдавать выводaaXXXABnnACss
, но ваша команда пропускает эту строку без изменений.Решение довольно простое.
.*
жадный, но не совсем жадный. Рассмотрим сопоставлениеssABteAstACABnnACss
с регулярным выражениемAB.*AC
. То,AC
что следует,.*
должно иметь совпадение. Проблема в том, что, поскольку.*
он жадный, последующийAC
будет соответствовать последнему,AC
а не первому..*
сгорает первым, вAC
то время как литералAC
в регулярном выражении совпадает с последним в ssABteAstACABnn AC ss. Чтобы этого не случилось, просто замените первоеAC
на что-то смешное, чтобы отличить его от второго и от всего остального.Жадный
.*
теперь остановиться у подножия-foobar-
вssABteAst-foobar-ABnnACss
потому , что нет другого ,-foobar-
чем это-foobar-
, и регулярное выражение-foobar-
должны иметь спичку. Предыдущая проблема заключалась в том, что регулярное выражениеAC
имело два совпадения, но из-за.*
жадностиAC
было выбрано последнее совпадение для . Однако, с-foobar-
, возможно только одно совпадение, и это совпадение доказывает, что.*
оно не является абсолютно жадным. Остановка автобуса.*
происходит, когда остается только одно совпадение для остальной части следующего регулярного выражения.*
.Обратите внимание, что это решение не будет выполнено, если
AC
перед первым появится значок,AB
потому что неправильныйAC
будет заменен на-foobar-
. Например, после первойsed
заменыACssABteAstACABnnACss
становится-foobar-ssABteAstACABnnACss
; следовательно, совпадение не может быть найдено противAB.*-foobar-
. Однако, если последовательность всегда ... AB ... AC ... AB ... AC ..., тогда это решение будет успешным.источник
Один из вариантов - изменить строку так, чтобы вы хотели жадного совпадения.
Используйте,
rev
чтобы перевернуть строку, отменить критерии соответствия, использоватьsed
обычным способом, а затем отменить результат ....источник