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

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

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

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

  • от А до Я; символы верхнего регистра
  • от А до Я; строчные буквы
  • от 0 до 9; числовые символы от 0 до 9
  • -; черточки

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

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

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

Ответы [ 6 ]

15 голосов
/ 14 января 2010
^(?![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
12 голосов
/ 07 сентября 2012

регулярное выражение Javascript, основанное на ответе Маркса:

pattern = /^(?![0-9]+$)(?!.*-$)(?!-)[a-zA-Z0-9-]{1,63}$/g;
3 голосов
/ 06 сентября 2013

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

\A(?![0-9]+$)(?!-)[a-zA-Z0-9-]{,63}(?<!-)\z
3 голосов
/ 20 марта 2012

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

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

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

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

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

2 голосов
/ 03 сентября 2015

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

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

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

2 голосов
/ 06 января 2014

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

Рубин: \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

Примечания:

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