Регулярные выражения: негативная ретроспективная проверка

Николай В.
На сайте с 07.09.2006
Offline
62
2467

Коллеги,

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

Пользователь вводит адрес страницы вида foo/bar.

Эти URI я проверяю на разрешенные символы [a-z0-9_\-/]+.

Кроме того необходимо отсечь URI, начинающиеся с подстроки admin.

По логике нужно что-то вроде (?<!admin)[a-z0-9_\-/]+

Однако ожидаемого Nope нижеприведенный код не выдает.


$str = "admin/test";
if (preg_match_all("#(?<!admin)[a-z0-9_\-/]+#", $str, $matches)) {
print_r($matches);
} else {
echo "Nope";
}

Аналогичная «позитивная» проверка (?<=) работает, как ожидается. ЧЯДНТ?

Str01tel
На сайте с 27.12.2009
Offline
26
#1

а так не проще ?

$str = "admin/test"; 
if (preg_match_all("#[a-z0-9_\-/]+#", $str, $matches) && !preg_match ('/^admin/i', $str)) {
print_r($matches);
} else {
echo "Nope";
}
edogs software
На сайте с 15.12.2005
Offline
775
#2

Негативная проверка подразумевает что у Вас не находится НИ ОДНОГО варианта который удовлетворял бы регу. А поскольку у Вас во второй части ( a-z0-9_\-/ ) множество в которое может войти очень много, в том числе ВСЁ выражение, то тут и вылезает ошибка.

Что убедится в этом, достаточно написать "#(?<!admin)([a-z0-9_\-/]+)#"

И сразу будет наглядно видно, что под условие [a-z0-9_\-/]+ попадает всё выражение целиком admin/test, ПЕРЕД которым действительно НЕТУ слова admin.

В Вашей ситуации вполне может подойти вариант

#(?<!admin)/([a-z0-9_\-/]+)#

Или что еще проще и правильнее (раз Вам нужно проверить только начало строки), просто проверяйте substr($url,0,5)!='admin'

И конечно надо помнить, что $_SERVER['REQUEST_URI'] обычно выглядит как /admin/test, а не как admin/test как в Вашем тестовом примере.

И еще момент, если Вы проверяете урл по $_SERVER['REQUEST_URI'], то не забывайте, что вызов например ad%6Din.php у Вас вызовет admin.php, но при этом в $_SERVER['REQUEST_URI'] у Вас не будет слова admin.

Разработка крупных и средних проектов. Можно с криптой. Разумные цены. Хорошее качество. Адекватный подход. Продаем lenovo legion в спб, дешевле магазинов, новые, запечатанные. Есть разные. skype: edogssoft
Николай В.
На сайте с 07.09.2006
Offline
62
#3
а так не проще ?

Проще, но мне нужно именно цельное выражение с отрицанием, чтобы запихнуть в Regeх-валидатор. Ну и сама матчасть интересна.

Z1
На сайте с 09.12.2005
Offline
164
#4

Будьте проще :) В одной регулярке проверяйте на разрешённые символы, во второй - на вхождение подстроки admin (наверное даже лучше с помощью strpos).

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

З.Ы. Пока писал - Вы все опередили :)

Николай В.
На сайте с 07.09.2006
Offline
62
#5

edogs, благодарю. Стало понятнее.

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий