Регулярное выражение для проверки метки DNS (имя хоста)
Я хотел бы проверить имя хоста, используя только выражение regualr.
Имена хостов (или "ярлыки" на DNS-жаргоне) традиционно определяются RFC 952 и RFC 1123 и могут состоять из следующих допустимых символов.
Элемент списка
- от А до Я; символы верхнего регистра
- от a до z; символы нижнего регистра
- от 0 до 9; числовые символы от 0 до 9
- -; тире
Правила говорят:
- Имя хоста (метка) может начинаться или заканчиваться буквой или числом
- Имя хоста (метка) НЕ ДОЛЖНО запускаться или заканчиваться символом '-' (тире)
- Имя хоста (метка) НЕ ДОЛЖНО состоять из всех числовых значений
- Имя хоста (метка) может содержать до 63 символов
Как бы вы пишете регулярное выражение для проверки имени хоста?
Ответы
Ответ 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
Примечания:
Ответ 6
Хотя принятый ответ верен, RFC2181 также указывается в разделе 11 "Синтаксис имен":
Сам DNS помещает только одно ограничение на определенные метки которые могут использоваться для идентификации записей ресурсов. Это одно ограничение относится к длине ярлыка и имени. [...] Реализации протоколов DNS не должны устанавливать никаких ограничений на этикетках, которые можно использовать. В частности, DNS-серверы не должны отказаться от обслуживания зоны, поскольку она содержит ярлыки, которые могут не быть приемлемый для некоторых клиентских программ DNS.
Это, в свою очередь, означает, что другие символы такие как символы подчеркивания, должны быть разрешены.