Отслеживает ли регулярное выражение имя хоста или IP-адрес? и используя Ограничения на допустимые имена хостов в качестве ссылки, каков наиболее читаемый и краткий способ сопоставления/проверки имени хоста /fqdn (полное доменное имя) в Python? Я ответил с моей попыткой ниже, улучшения приветствуются.
Проверка строки имени хоста
Ответ 1
import re
def is_valid_hostname(hostname):
if len(hostname) > 255:
return False
if hostname[-1] == ".":
hostname = hostname[:-1] # strip exactly one dot from the right, if present
allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
return all(allowed.match(x) for x in hostname.split("."))
гарантирует, что каждый сегмент
- содержит хотя бы один символ и максимум 63 символа.
- состоит только из разрешенных символов
- не начинается или не заканчивается дефисом.
Он также избегает двойных негативов (not disallowed
), а если hostname
заканчивается на .
, это тоже ОК. Он будет (и должен) сбой, если hostname
заканчивается более чем на одну точку.
Ответ 2
Здесь немного более строгая версия Tim Pietzcker ответ со следующими улучшениями:
- Ограничьте длину имени хоста 253 символами (после удаления необязательной конечной точки).
- Ограничьте набор символов в ASCII (т.е. используйте
[0-9]
вместо\d
). - Убедитесь, что TLD не является числовым.
import re
def is_valid_hostname(hostname):
if hostname[-1] == ".":
# strip exactly one dot from the right, if present
hostname = hostname[:-1]
if len(hostname) > 253:
return False
labels = hostname.split(".")
# the TLD must be not all-numeric
if re.match(r"[0-9]+$", labels[-1]):
return False
allowed = re.compile(r"(?!-)[a-z0-9-]{1,63}(?<!-)$", re.IGNORECASE)
return all(allowed.match(label) for label in labels)
Ответ 3
Per Старая новая вещь, максимальная длина имени DNS составляет 253 символа. (Один разрешен до 255 октетов, но 2 из них потребляются кодировкой.)
import re
def validate_fqdn(dn):
if dn.endswith('.'):
dn = dn[:-1]
if len(dn) < 1 or len(dn) > 253:
return False
ldh_re = re.compile('^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$',
re.IGNORECASE)
return all(ldh_re.match(x) for x in dn.split('.'))
Можно утверждать, что вы принимаете пустые имена доменов или нет, в зависимости от одной цели.
Ответ 4
Мне нравится тщательность ответа Тима Пицккера, но я предпочитаю разгрузить часть логики из регулярных выражений для удобочитаемости. Честно говоря, мне пришлось искать смысл этих частей (?
"нотации". Кроме того, я считаю, что подход с "двойным отрицанием" более очевиден в том смысле, что он ограничивает ответственность регулярного выражения просто нахождением какого-либо недопустимого характера. Мне нравится, что re.IGNORECASE позволяет сократить регулярное выражение.
Итак, вот еще один выстрел; он длиннее, но он читает вроде прозы. Я полагаю, что "читаемый" несколько расходится с "кратким". Я считаю, что все ограничения проверки, упомянутые в потоке до сих пор, охватываются:
def isValidHostname(hostname):
if len(hostname) > 255:
return False
if hostname.endswith("."): # A single trailing dot is legal
hostname = hostname[:-1] # strip exactly one dot from the right, if present
disallowed = re.compile("[^A-Z\d-]", re.IGNORECASE)
return all( # Split by labels and verify individually
(label and len(label) <= 63 # length is within proper range
and not label.startswith("-") and not label.endswith("-") # no bordering hyphens
and not disallowed.search(label)) # contains only legal characters
for label in hostname.split("."))
Ответ 5
def is_valid_host(host):
'''IDN compatible domain validator'''
host = host.encode('idna').lower()
if not hasattr(is_valid_host, '_re'):
import re
is_valid_host._re = re.compile(r'^([0-9a-z][-\w]*[0-9a-z]\.)+[a-z0-9\-]{2,15}$')
return bool(is_valid_host._re.match(host))
Ответ 6
Дополнительно к ответу @TimPietzcker. Подчеркивание - это допустимое имя хоста (не доменное имя), двойная черта обычно встречается для домена с произвольным кодом IDN (например, xn--). Номер порта должен быть удален. Это очистка кода.
import re
def is_valid_hostname(hostname):
if len(hostname) > 255:
return False
hostname = hostname.rstrip(".")
allowed = re.compile("(?!-)[A-Z\d\-\_]{1,63}(?<!-)$", re.IGNORECASE)
return all(allowed.match(x) for x in hostname.split("."))
# convert your unicode hostname to punycode (python 3 )
# Remove the port number from hostname
normalise_host = hostname.encode("idna").decode().split(":")[0]
is_valid_hostanme(normalise_host )
Ответ 7
Это чистое регулярное выражение должно соответствовать всем параметрам: ^(?=.{1,253}\.?$)(?!-)[A-Za-z0-9\-]{1,63}(\.[A-Za-z0-9\-]{1,63})*\.?(?<!-)$
Ответ 8
Обработать каждую метку DNS отдельно, исключив недопустимые символы и обеспечив ненулевую длину.
def isValidHostname(hostname):
disallowed = re.compile("[^a-zA-Z\d\-]")
return all(map(lambda x: len(x) and not disallowed.search(x), hostname.split(".")))
Ответ 9
Если вы хотите проверить имя существующего хоста, лучше всего попытаться его решить. Вы никогда не будете писать регулярное выражение, чтобы обеспечить этот уровень проверки.