Подтвердить что ты не робот

Регулярное выражение для проверки метки DNS (имя хоста)

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

Имена хостов (или "ярлыки" на DNS-жаргоне) традиционно определяются RFC 952 и RFC 1123 и могут состоять из следующих допустимых символов.

Элемент списка

  • от А до Я; символы верхнего регистра
  • от a до z; символы нижнего регистра
  • от 0 до 9; числовые символы от 0 до 9
  • -; тире

Правила говорят:

  • Имя хоста (метка) может начинаться или заканчиваться буквой или числом
  • Имя хоста (метка) НЕ ДОЛЖНО запускаться или заканчиваться символом '-' (тире)
  • Имя хоста (метка) НЕ ДОЛЖНО состоять из всех числовых значений
  • Имя хоста (метка) может содержать до 63 символов

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

4b9b3361

Ответ 1

^(?![0-9]+$)(?!-)[a-zA-Z0-9-]{,63}(?<!-)$

Я использовал следующий тестовый файл, написанный на Python, чтобы убедиться, что он работает правильно:

tests = [
    ('01010', False),
    ('abc', True),
    ('A0c', True),
    ('A0c-', False),
    ('-A0c', False),
    ('A-0c', True),
    ('o123456701234567012345670123456701234567012345670123456701234567', False),
    ('o12345670123456701234567012345670123456701234567012345670123456', True),
    ('', True),
    ('a', True),
    ('0--0', True),
]

import re
regex = re.compile('^(?![0-9]+$)(?!-)[a-zA-Z0-9-]{,63}(?<!-)$')
for (s, expected) in tests:
    is_match = regex.match(s) is not None
    print is_match == expected

Ответ 2

Javascript regex на основе ответа Marks:

pattern = /^(?![0-9]+$)(?!.*-$)(?!-)[a-zA-Z0-9-]{1,63}$/g;

Ответ 3

Регулярные выражения Ruby по умолчанию являются многострочными, поэтому что-то вроде Rails предупреждает об использовании ^ и $. Это ответ Mark с безопасным стартом и концом строковых символов:

\A(?![0-9]+$)(?!-)[a-zA-Z0-9-]{,63}(?<!-)\z

Ответ 4

Стоит отметить, что DNS-метки и компоненты имени хоста имеют несколько иные правила. В первую очередь: "_" не является законным в любом компоненте имени хоста, но является стандартной частью меток, используемых для таких вещей, как записи SRV.

Более читаемый и переносимый подход требует, чтобы строка соответствовала и этих POSIX ERE:

^[[:alnum:]][[:alnum:]\-]{0,61}[[:alnum:]]|[[:alpha:]]$
^.*[[:^digit:]].*$

Те должны быть просты в использовании в любой стандартной совместимой реализации ERE. Perl-стиль backtracking, как и в примере Python, широко доступен, но проблема заключается не в том, чтобы быть абсолютно одинаковым везде, где он работает. Уч.

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

Ответ 5

Пересмотренное регулярное выражение на основе комментариев здесь и мое собственное чтение RFC 1035 и 1123:

Ruby: \A(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\z (тесты ниже)

Python: ^(?!-)[a-zA-Z0-9-]{1,63}(?<!-)$ (не проверено мной)

Javascript: pattern = /^(?!-)[a-zA-Z0-9-]{1,63}$/g; (на основе ответа Тома Лайма, не проверенного мной)

Тесты:

tests = [
  ['01010', true],
  ['abc', true],
  ['A0c', true],
  ['A0c-', false],
  ['-A0c', false],
  ['A-0c', true],
  ['o123456701234567012345670123456701234567012345670123456701234567', false],
  ['o12345670123456701234567012345670123456701234567012345670123456', true],
  ['', false],
  ['a', true],
  ['0--0', true],
  ["A0c\nA0c", false]
]

regex = /\A(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\z/
tests.each do |label, expected|
  is_match = !!(regex =~ label)
  puts is_match == expected
end

Примечания:

  • Спасибо Mark Byers за исходный фрагмент кода
  • solidsnack указывает, что RFC 1123 позволяет использовать все числовые метки (https://tools.ietf.org/html/rfc1123#page-13)
  • RFC 1035 не допускает метки нулевой длины (https://tools.ietf.org/html/rfc1035): <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
  • Я добавил тест специально для Ruby, который гарантирует, что новая строка не встроена в метку. Это благодаря заметкам ssorallen.
  • Этот код доступен здесь: https://github.com/Xenapto/domain-label-validation - Я рад принять запросы на загрузку, если вы хотите его обновить.

Ответ 6

Хотя принятый ответ верен, RFC2181 также указывается в разделе 11 "Синтаксис имен":

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

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