Регулярное выражение для маршрутизации URL-адресов — соответствие буквенно-цифровым символам и дефисам, кроме слов в этом списке

Я использую CodeIgniter для написания приложения, в котором пользователю будет разрешено зарегистрировать учетную запись, и ему будет назначен URL-адрес (слаг URL-адреса) по их выбору (например, domain.com/user-name). CodeIgniter имеет функцию маршрутизации URL-адресов, которая позволяет использовать регулярные выражения (ссылка ).

Пользователям разрешено регистрировать только те URL-адреса, которые содержат буквенно-цифровые символы, дефисы (-) и знаки подчеркивания (_). Это регулярное выражение, которое я использую для проверки правильности URL-адреса: ^[A-Za-z0-9][A-Za-z0-9_-]{2,254}$

Я использую функцию маршрутизации URL-адресов, чтобы направить несколько URL-адресов на функции на моем сайте (например, /home -> /pages/index, /activity -> /user/activity), поэтому эти конкретные URL-адреса, очевидно, не могут быть зарегистрированы пользователем.

Я в значительной степени неопытен с регулярными выражениями, но попытался написать выражение, которое будет соответствовать любым URL-адресам с буквенно-цифровыми символами/тире/подчеркиванием, за исключением случаев, когда они являются одним из следующих:

  1. default_controller
  2. 404_переопределить
  3. домой
  4. Мероприятия

Вот код, который я использую, чтобы попытаться сопоставить слова с этими конкретными критериями:

$route['(?!default_controller|404_override|home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254}'] = 'view/slug/$1';

но он не маршрутизируется должным образом. Кто-нибудь может помочь? (дополнительный вопрос: необходимо ли иметь ^ или $ в регулярном выражении при попытке сопоставить URL?)


person Zaki Aziz    schedule 02.04.2013    source источник


Ответы (3)


Хорошо, давайте разберём это.

Игнорировать зарезервированные маршруты CodeIgniter.

Части default_controller и 404_override маршрута не нужны. Маршруты сравниваются с запрошенным URI, чтобы увидеть, есть ли совпадения. Маловероятно, что эти два элемента когда-либо будут в вашем URI, поскольку они являются специальными зарезервированными маршрутами для CodeIgniter. Так что давайте забудем о них.

$route['(?!home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254}'] = 'view/slug/$1';

Запечатлейте все!

При использовании регулярных выражений группа создается с помощью круглых скобок (). Затем эту группу можно получить по обратной ссылке — в нашем случае $1, $2, etc., расположенной во второй части маршрута. У вас была группа только вокруг первого набора элементов, которые вы пытались исключить, поэтому он не мог правильно захватить весь подстановочный знак. Вы уже сами это выяснили и добавили группу вокруг всего элемента (хорошо!).

$route['((?!home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254})'] = 'view/slug/$1';

Прогноз?!

По этому вопросу первая группа вокруг home|activity на самом деле не является традиционной группой из-за использования ?! в начале. Это называется упреждающим отрицательным анализом и представляет собой сложную функцию регулярного выражения. И он используется неправильно:

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

Я мог бы рассказать об этом НАМНОГО больше, но в основном мы не хотим и не нуждаемся в этом с самого начала, поэтому я позволю вам исследовать, если хотите.

Чтобы облегчить вам жизнь, я предлагаю разделить в маршрутах home, activity и другие существующие контроллеры. CodeIgniter просматривает список маршрутов сверху вниз и, как только что-то совпадает, прекращает проверку. Таким образом, если вы укажете свои существующие контроллеры перед подстановочным знаком, они будут совпадать, и ваше регулярное выражение подстановочного знака может быть значительно упрощено.

$route['home'] = 'pages';
$route['activity'] = 'user/activity';
$route['([A-Za-z0-9][A-Za-z0-9_-]{2,254})'] = 'view/slug/$1';

Не забудьте перечислить свои маршруты в порядке от наиболее конкретного к наименее. Совпадения с подстановочными знаками менее специфичны, чем точные совпадения (например, дом и активность), поэтому они должны следовать после (ниже).

Вот и все сложные вещи. Еще немного к вашему сведению.

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

$route['([A-Za-z0-9][A-Za-z0-9_\-]{2,254})'] = 'view/slug/$1';

Обратите внимание, что повторение вашего символа min/max {2,254} применяется только ко второму набору символов, поэтому ваши имена пользователей должны состоять минимум из 3 символов и максимум из 255. Просто к вашему сведению, если вы еще этого не поняли.

Я видел ваш собственный ответ на эту проблему, и это просто некрасиво. Прости. Символы ^ и $ используются некорректно во всем упреждающем просмотре (которого все равно не должно быть в первую очередь). Это может «работать» для нескольких вариантов использования, с которыми вы его тестируете, но в будущем это просто создаст вам проблемы и головную боль.

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

И чтобы ответить на ваш вопрос, нет, вы не должны использовать ^ и $ в начале и в конце вашего регулярного выражения - CodeIgniter добавит это за вас.


Используй 404, Люк...

На данный момент ваши маршруты улучшены и должны быть функциональными. Тем не менее, я добавлю его туда, что вы, возможно, захотите рассмотреть возможность использования контроллера/метода, определенного как 404_override, для обработки ваших подстановочных знаков. Основное преимущество этого заключается в том, что вам не нужны НИКАКИЕ маршруты для направления подстановочного знака или для предотвращения того, чтобы ваш подстановочный знак искажал существующие контроллеры. Вам нужно только:

$route['404_override'] = 'view/slug';

Затем ваш метод View::slug() проверит URI и увидит, является ли он допустимым шаблоном, а затем проверит, существует ли он как пользователь (то же самое, что и ваш метод slug сейчас, без сомнения). Если это так, то вы можете идти. Если это не так, вы выдаете ошибку 404.

Это может показаться не таким изящным, но работает отлично. Попробуйте, если это звучит лучше для вас.

person Aken Roberts    schedule 02.04.2013
comment
Спасибо за этот отличный ответ. Вы не только помогли мне ответить на мои вопросы, вы также помогли мне узнать несколько новых вещей, которые заставили меня смотреть на вещи немного по-другому. Спасибо. - person Zaki Aziz; 03.04.2013

Я не знаком конкретно с codeIgniter, но большинство фреймворков маршрутизации работают на основе приоритета. Другими словами, контроллер по умолчанию, маршруты 404 и т. д. должны быть определены в первую очередь. Затем вы можете упростить регулярное выражение, чтобы оно соответствовало только слагам.

person Marcos Savoury    schedule 02.04.2013

Хорошо, отвечая на мой собственный вопрос

Кажется, я придумал другое выражение, которое работает:

$route['(^(?!default_controller$|404_override$|home$|activity$)[A-Za-z0-9][A-Za-z0-9_-]{2,254}$)'] = 'view/slug/$1';

Я добавил круглые скобки вокруг всего выражения (я думаю, это то, что CodeIgniter сопоставляет с $1 справа) и добавил идентификатор начала строки: ^ и набор идентификаторов конца строки: $

Надеюсь, это поможет кому-то, кто может столкнуться с этой проблемой позже.

person Zaki Aziz    schedule 02.04.2013