ретроспективная проверка

Статус
В этой теме нельзя размещать новые ответы.

Casper_R

Создатель
Регистрация
2 Май 2007
Сообщения
88
Реакции
33
Господа, подскажите. Я что-то никак не пойму, почему не работает негативная ретроспективная проверка "(?<!ya\.ru)" Эта зараза должна откидывать ya.ru линки, ан нет. Уже устал блин разбираться... хэлп плиз

PHP:
$data = <<<EOD
<a href="http://www.ya.ru/adasd/">Hi Fred</a><br>
<a href="http://www.me.ru/foo/">Hi Fred</a><br>
EOD;
$regex = '/href=(?:["\'])?(?:http:\/\/)?(?:www\.)?(?<!ya\.ru)[a-z0-9A-Z.]+(?:["\'])?/';
preg_match_all($regex,$data,$out);
echo "<pre>",print_r($out),"</pre>";


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

Darkmind

SNMP maniac
Регистрация
31 Май 2006
Сообщения
185
Реакции
82
Ретроспективная проверка не вернёт false всему match'у на данной итерации. Поскольку регулярное выражение разбирается пошагово, ?<! отклоняет предыдущий match, т.е. (?:www\.). А далее идёт условие [a-z0-9A-Z.], которое снова ловит все, начиная с www.

Поэтому необходимо использовать опережающую проверку (?!), сразу отбрасывая строки, содержащие искомую подстроку.
Упрощённо:
PHP:
$regex = '/^(?!.*ya\.ru)(?:.*)/m';
Приведя к исходному виду, получим:
PHP:
$regex = '%(?!.*ya\.ru)href=(?:["\'])?(?:http://)?(?:www\.)?[a-z0-9A-Z.]+%m';
Могу ошибаться, но мне кажется preg_match_all не подходит для этой задачи. stripos существенно быстрее и удобнее, что собственно и указывается в официальной документации.
 

Casper_R

Создатель
Регистрация
2 Май 2007
Сообщения
88
Реакции
33
спасибо большое. ближе к утру я допер до того, что ретроспективные проверки идут одна за другой, причем независимо.
в итоге был изобретен такой костыль:

PHP:
$regex = '#(?<=href=["\'](?!.*ya.ru))(.*)(?=["\'])#';

условная "хитрость" в том, что ретроспективная проверка ?<=... НЕ ЗАКРЫВАЕТСЯ, а сразу за ней идет опережающая негативная и уже потом закрываются обе скобками - ))

плюсов вижу один - проверки идут по порядку так, как это должно выглядеть по логике.

однако твой пример не такой громоздкий, но я не очень понимаю, как это работает, что опережающая проверка (?!.*ya\.ru) , чекает весь матч... :( просто в логику не воткну (вопрос скорее риторический и апеллирует, более к недостаточному опыту).

что касается "stripos", то по условию задачи надо выловленные регэкспом URL использовать для дальнейшей работы. stripos такого функционала не предоставляет и лишь говорит - да/нет.
 

Darkmind

SNMP maniac
Регистрация
31 Май 2006
Сообщения
185
Реакции
82
Я специально оставил сокращённый вариант, в нём логику проще уловить. Опережающая проверка (?!) работает как простое условие if(! ... ) "если не". Если строка не матчится регекспом .*ya\.ru, то разгребаем его дальше. Если матчится, то вернётся false.

Это исключает вариант, когда регэксп выдирал Для просмотра ссылки Войди или Зарегистрируйся наталкивался на ya.ru и отбрасывал все, что идёт дальше, но http:// сохранялось и в итоге строка проходила "валидацию".

P.S. Рекомендую попробовать программку RegexBuddy. В режиме отладки писать регулярки - одно удовольствие. Сэкономила бы кучу времени, показав пошагово, как разбирается регулярка и что проверка отбрасывает "шаг назад".
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху