Правильное сопоставление URL-адреса IDN

Мне нужна помощь в создании регулярного выражения, которое может правильно сопоставлять URL-адрес внутри свободного текста.

  • scheme
    • One of the following: ftp, http, https (is ftps a protocol?)
  • необязательный пользователь (и необязательный пароль)
  • host (with support for IDNs)
    • support for www and sub-domain(s) (with support for IDNs)
    • базовая фильтрация TLD (я думаю, [a-zA-Z]{2,6} достаточно)
  • необязательный номер порта
  • путь (необязательно, с поддержкой символов Unicode)
  • запрос (необязательно, с поддержкой символов Unicode)
  • фрагмент (необязательно, с поддержкой символов Unicode)

Вот что я смог узнать о поддоменах:

«Поддомен» выражает относительную, а не абсолютную зависимость: например, wikipedia.org включает поддомен домена org, а en.wikipedia.org включает поддомен домена wikipedia.org. Теоретически это подразделение может иметь глубину до 127 уровней, а каждая метка DNS может содержать до 63 символов, если общая длина доменного имени не превышает 255 символов.

Что касается самого доменного имени, я не смог найти надежного источника, но я думаю, что регулярное выражение для не-IDN (я не знаю, как написать версию, совместимую с IDN) выглядит примерно так:

[0-9a-zA-Z][0-9a-zA-Z\-]{2,62}

Может ли кто-нибудь помочь мне с этим регулярным выражением или указать правильное направление?


person Alix Axel    schedule 29.12.2009    source источник
comment
Что касается поддержки IDN, вы имеете в виду, что он должен поддерживать www.emilvikström.se или только версию punycode www.xn--emilvikstrm-0fb.se?   -  person Emil Vikström    schedule 29.12.2009
comment
@Emil: emilvikström.se, я считаю, что мне нужно использовать свойство \p{L}, но я не уверен.   -  person Alix Axel    schedule 29.12.2009


Ответы (3)


Джон Грубер, известный по Daring Fireball, недавно опубликовал публикацию, в которой подробно описал свои поиски хорошего URL. -распознавание строки регулярного выражения. Вот что он придумал:

\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))

Что, по-видимому, хорошо работает и с URL-адресами, содержащими Unicode. Вам потребуется немного изменить его, чтобы получить остальную часть того, что вы ищете — схему, имя пользователя, пароль и т. д. Алан Сторм написал статью, объясняющую паттерн регулярных выражений Грубера, который мне определенно был нужен (регулярные выражения — это когда-то-напиши-не-понять-как-читать-всегда-снова!).

person delfuego    schedule 29.12.2009
comment
Вероятно, это хорошо, если вы добавите часть имени пользователя и пароля ( protocol://username:[email protected]/path?querystring#anchor ) - person Emil Vikström; 29.12.2009
comment
Я протестировал этот шаблон, и он работает, чтобы получить весь URL-адрес. Может быть, проще всего потом просто запустить найденные URL через parse_url(). - person Emil Vikström; 29.12.2009
comment
@delfuego: Чем это регулярное выражение отличается от этого (?:[\w-]+://?|www[.])[^\s<>]+(?:[^[:punct:]\s]|/)? - person Alix Axel; 30.12.2009
comment
Аликс, посмотри на связанную часть Алана Сторма в моем комментарии для объяснения каждой части строки регулярного выражения Джона Грубера, и тогда ты увидишь, чего не хватает в твоей. - person delfuego; 30.12.2009
comment
@Emil: Эта функция parse_url не предназначена для проверки данного URL-адреса, она только разбивает его на перечисленные выше части. И расширение filter не может проверить URL-адреса IDN. - person Alix Axel; 14.01.2010
comment
@ Аликс, это правильно. Таким образом, в этом случае регулярное выражение обрабатывает поиск допустимых URL-адресов, а затем функция parse_url разбивает проверенные URL-адреса на их составные части. - person delfuego; 14.01.2010

Если вам нужен протокол и вы не слишком беспокоитесь о ложных срабатываниях, то проще всего сопоставить все непробельные символы вокруг ://.

person Scott Saunders    schedule 29.12.2009
comment
чтобы исключить ложные, пропустите результаты через filter_var и, если это не вернет false, пропустите его через parse_url, чтобы получить компоненты. - person Gordon; 29.12.2009

Это поможет вам пройти большую часть пути. Если вам нужна более доработанная версия, пожалуйста, предоставьте тестовые данные.

(ftp|https?)://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?
person ennuikiller    schedule 29.12.2009
comment
Это правильный URL? из ietf.org/rfc/rfc1738.txt ... только буквенно-цифровые символы, специальные символы $-_.+!*'(), а зарезервированные символы, используемые для их зарезервированных целей, могут использоваться незакодированными в URL-адресе. - person PA.; 29.12.2009
comment
См. RFC3490 об интернационализированных доменных именах. С технической точки зрения, такой как DNS, он всегда преобразуется в punycode, но отображается в приложениях с международными символами. - person Emil Vikström; 29.12.2009