Regex - вложенные шаблоны - внутри внешнего шаблона, но исключают внутренний шаблон - PullRequest
1 голос
/ 08 июня 2011

У меня есть файл с содержанием ниже.

<td> ${ dontReplaceMe } ReplaceMe ${dontReplaceMeEither} </td>

Я хочу сопоставить 'ReplaceMe', если оно есть в теге td, но НЕ, если оно есть в выражении $ {...}.

Могу ли я сделать это с помощью регулярных выражений?

В настоящее время есть:

sed '/\${.*?ReplaceMe.*?}/!s/ReplaceMe/REPLACED/g' data.txt

Ответы [ 5 ]

9 голосов
/ 08 июня 2011

Это невозможно.

Regex можно использовать для языков хомского типа-3 (обычный язык).
Однако ваш пример кода - язык Хомского типа-2 (контекстно-свободный язык).

Практически, как только вложены любые виды вложений (скобок), вы имеете дело с контекстно-свободными языками, которые не охватываются регулярными выражениями.

Существует в основном , никак не для определения within a pair of x and y в регулярном выражении , так как требует, чтобы регулярное выражение имело некоторый вид стека, который он не (будучи функционально эквивалентным автомату конечных состояний).


Brandizzi предложила найти регулярное выражение, которое могло бы соответствовать хотя бы тривиальным случаям
Я на самом деле придумал этот (мучительно хакерский) шаблон регулярного выражения:

perl -pe 's/(?<=<td>)((?:(?:\{.*?\})*[^{]*?)*)(ReplaceMe)(.*)(?=<\/td>)/$1REPLACED$3/g'

Это правильно (sic!) совпадение для этих случаев:

<td> ${ dontReplaceMe } ReplaceMe ${dontReplaceMeEither} </td>
<td> ReplaceMe ${dontReplaceMeEither} </td>
<td> ${ dontReplaceMe } ReplaceMe </td>
<td> ReplaceMe </td>

И терпит неудачу с этим (вложение - это Хомский Тип-2, помните?;)) :

<td>${ ${ dontReplaceMe } ReplaceMe ${dontReplaceMeEither} }</td>

И не может заменить несколько совпадений :

<td> ReplaceMe ReplaceMe </td>
<td> ReplaceMe ${dontReplaceMeEither} ReplaceMe </td>

Получение ведущей информации $ было сложной задачей.
Это и не дает Реджинальду / Регги постоянно падать при написании этого зверя.

ВНОВЬ: ЭКСПЕРИМЕНТАЛЬНО, НИКОГДА НЕ ИСПОЛЬЗУЙТЕ ЭТО В КОДЕКСЕ ПРОИЗВОДСТВА!

(… или я буду выслеживать вас, если мне когда-нибудь придется работать с вашим кодом / приложением;)

1 голос
/ 08 июня 2011

обычно плохая идея использовать регулярные выражения, когда используется структурированная разметка.в некоторых особых случаях это может быть нормально, но есть лучшие инструменты для анализа html и , чем , вы можете использовать регулярные выражения в текстовых узлах.

1 голос
/ 08 июня 2011

Ну, в таком простом случае вам просто нужно убедиться, что строка не соответствует ${.*}:

$ sed '/\${.*}/!s/ReplaceMe/REPLACED/' input
<td> REPLACED </td>
<td> ${ don't ReplaceMe } </td>

! после /\${.*}/ sedaddress отрицает критерии.

OTOH, если дело не так просто, я подозреваю, что ваша проблема сильно вырастет, и регулярное выражение не будет лучшим решением.

0 голосов
/ 08 июня 2011
sed -i 's/<td>\sReplaceMe\s<\/td>/<td>Replaced<\/td>/gi' input.file

работал на меня.

Вы можете использовать -i.bak для резервного копирования старого файла, в случае ошибки.

альтернативно

perl -pi -e 's/<td>\sReplaceMe\s<\/td>/<td>Replaced<\/td>/g' temp

также работает, опять же, обратите внимание на -pi.bak для резервного копирования.

0 голосов
/ 08 июня 2011

Что-то вроде <td>.*(?<!${).*ReplaceMe(?!.*}).*</td> должно работать, если grep поддерживает отрицательные взгляды (не помню, работает ли).

...