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

Тема в разделе "PHP Pro", создана пользователем Casper_R, 21 июн 2011.

Статус темы:
Закрыта.
  1. Casper_R

    Casper_R Создатель

    Регистр.:
    3 май 2007
    Сообщения:
    87
    Симпатии:
    25
    Господа, подскажите. Я что-то никак не пойму, почему не работает негативная ретроспективная проверка "(?<!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>";

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

    Darkmind SNMP maniac

    Регистр.:
    31 май 2006
    Сообщения:
    184
    Симпатии:
    76
    Ретроспективная проверка не вернёт 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 нравится это.
  3. Casper_R

    Casper_R Создатель

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

    PHP:
    $regex '#(?<=href=["\'](?!.*ya.ru))(.*)(?=["\'])#';
    условная "хитрость" в том, что ретроспективная проверка ?<=... НЕ ЗАКРЫВАЕТСЯ, а сразу за ней идет опережающая негативная и уже потом закрываются обе скобками - ))

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

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

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

    Darkmind SNMP maniac

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

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

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