Проверьте строку запроса URL с помощью регулярного выражения

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

Итак, это были бы предпосылки:

  • Это должно начинаться с вопросительного знака.
  • Он может содержать ключи со значениями или без значений, разделенных знаком равенства, пары, разделенные амперсандом.

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

#^\?([\w\-]+((&|=)([\w\-]+)*)*)?$#

Это правильно совпадает ?abc=123&def=345, но это также неправильно соответствует, например, ?abc=123=456,

Я мог бы пойти излишне и сделать что-то вроде...

/^\?([\w\-]+=?([\w\-]+)?(&[\w\-]+(=?[\w\-]*)?)*)?$/

... но я не хочу повторять одинаковые группы совпадений.

Как я могу сказать регулярному выражению, что разделители между значениями должны перебирать & а также = без повторения совпадений групп или отслеживания катастрофического спина?

Спасибо.

Редактировать:

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

7 ответов

Решение

Кажется, это то, что вы хотите:

^\?([\w-]+(=[\w-]*)?(&[\w-]+(=[\w-]*)?)*)?$

Посмотреть демо

Это рассматривает каждую "пару" как ключ, за которым следует необязательное значение (которое может быть пустым), и имеет первую пару, за которой следует необязательное & затем другая пара, и все выражение (за исключением ведущих?) не является обязательным. Это предотвращает совпадение ?&abc=def

Также обратите внимание, что дефис не нужно экранировать, когда он последний в классе символов, что позволяет немного упростить.

Кажется, вы хотите разрешить дефисы в любом месте ключей или значений. Если ключи должны быть свободны от дефисов:

^\?(\w+(=[\w-]*)?(&\w+(=[\w-]*)?)*)?$

Вы можете использовать это регулярное выражение:

^\?([^=]+=[^=]+&)+[^=]+(=[^=]+)?$

Что это делает:

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  ^                        the beginning of the string
--------------------------------------------------------------------------------
  \?                       '?'
--------------------------------------------------------------------------------
  (                        group and capture to \1 (1 or more times
                           (matching the most amount possible)):
--------------------------------------------------------------------------------
    [^=]+                    any character except: '=' (1 or more
                             times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
    =                        '='
--------------------------------------------------------------------------------
    [^=]+                    any character except: '=' (1 or more
                             times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
    &                        '&'
--------------------------------------------------------------------------------
  )+                       end of \1 (NOTE: because you are using a
                           quantifier on this capture, only the LAST
                           repetition of the captured pattern will be
                           stored in \1)
--------------------------------------------------------------------------------
  [^=]+                    any character except: '=' (1 or more times
                           (matching the most amount possible))
--------------------------------------------------------------------------------
  (                        group and capture to \2 (optional
                           (matching the most amount possible)):
--------------------------------------------------------------------------------
    =                        '='
--------------------------------------------------------------------------------
    [^=]+                    any character except: '=' (1 or more
                             times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
  )?                       end of \2 (NOTE: because you are using a
                           quantifier on this capture, only the LAST
                           repetition of the captured pattern will be
                           stored in \2)
--------------------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string

Я согласен с Энди Лестером, но возможное решение для регулярных выражений

#^\?([\w-]+=[\w-]*(&[\w-]+=[\w-]*))?$#

что очень похоже на то, что вы опубликовали.

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

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

В PHP используйте parse_url функция.

Perl: URI модуль.

Рубин: URI модуль.

.NET: класс "Ури"

Я сделал это.

function isValidURL(url) {
  // based off https://mathiasbynens.be/demo/url-regex. testing https://regex101.com/r/pyrDTK/2
  var pattern = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:\/?)(?:(?:\?(?:(?!&|\?)(?:\S))+=(?:(?!&|\?)(?:\S))+)(?:&(?:(?!&|\?)(?:\S))+=(?:(?!&|\?)(?:\S))+)*)?$/iuS;
  return pattern.test(url);
}

База: https://mathiasbynens.be/demo/url-regex

Тестирование: https://regex101.com/r/pyrDTK/4/

      /^\?([\w-]+(=[\w.\-:%+]*)?(&[\w-]+(=[\w.\-:%+]*)?)*)?$/

\w = [a-zA-Z0-9_]

? знак равно

над поддержкой регулярных выражений, a-z A-Z 0-9 _ . - : % +в значении параметра

вы можете проверить это регулярное выражение здесь

Когда вам нужно проверить очень сложный URL-адрес, вы можете использовать это регулярное выражение

`^(https|ftp|http|ftps):\/\/([a-z\d_]+\.)?(([a-zA-Z\d_]+)(\.[a-zA-Z]{2,6}))(\/[a-zA-Z\d_\%\-=\+]+)*(\?)?([a-zA-Z\d=_\+\%\-&\{\}\:]+)?`
Другие вопросы по тегам