AlexeyGfi
@AlexeyGfi
YouTube >>> Битриксоид из Колхоза

Как правильно применить отрицание в регулярных выражениях?

Добрый день!
Подскажите, как правильно настроить регулярное выражение?

Есть строка:
$str= '
текст 1
<a class="btn" href="https://site.ru/">Ссылка1</a>
текст 2
<a href="https://match.com/">Ссылка2</a>
текст 3
<a class="btn" href="https://fall.com/">Ссылка3</a>
текст 4';


Правильно работают выборки:
Удалить все ссылки, в которых содержится class:
echo preg_replace( '~<(a)[^>]class[^>]*>~siu', "", $str );

Удалить все ссылки, в которых не содержится class:
echo preg_replace( '~<(a)[^>](?!class)[^>]*>~siu', "", $str );


Отодвигаюсь внутрь тега.
Успешно удаляются все ссылки, которые ссылаются на сайт, в названии которого встречается match:
echo preg_replace( '~<(a)[^>]*?match[^>]+>[^<]+<\/\1>~siu', "", $str );


А вот обратная задача: удалить все ссылки, в которых не содержится match, у меня не получается (чистятся все теги).
Аналогично: рабочая выборка из первого примера перестаёт работать, как только добавляю модификатор * или +
<(a)[^>]class[^>]*>
<(a)[^>]+class[^>]*>

Подскажите, как правильно сделать?
https://regex101.com/r/suCdNB/2
  • Вопрос задан
  • 406 просмотров
Решения вопроса 1
AlexeyGfi
@AlexeyGfi Автор вопроса
YouTube >>> Битриксоид из Колхоза
Удалось расковырять самому.
https://regex101.com/r/suCdNB/4/

Основываясь на условных подмасках:
php.net/manual/ru/regexp.reference.conditional.php
а именно:
(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)


Наш анализ сводится к такому: «Если выполняется условие "не содержится match", мы применяем шаблон [^>] (который соответствует телу тега <a=тело=>), иначе (если match присутствует), применяем пустой шаблон (то есть пытаемся найти пустой тег <a>)».

Пустые теги <a> теоретически возможны (хоть и с точки зрения внедрения ссылки в текст безопасны), а значит наша регулярка не даёт железно 100%-результат. Потому в качестве no-pattern-а можно дать любую невалидную абракадабру (просто, чтобы её не было найдено).

<(a)(?(?!match)[^>]|false)+>[^<]*</\1>
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы