После Regular expression to match hostname or IP Address? и используя Restrictions on valid host names в качестве ссылки, что является наиболее читаемым, сжатым способом сопоставления/проверки имени хоста/fqdn (полное доменное имя) в Python? Я ответил с моей попыткой ниже, улучшения приветствуются.Подтвердить строку имени хоста
ответ
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
заканчивается более чем одной точкой.
Обработать каждую метку 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(".")))
'возврата всех (х, а не disallowed.search (х) при х в hostname.split (""))' – 2010-03-28 06:44:01
трейлинг '.' на конце имени хоста является действительным. О, и многое другое нужно сделать, если вы хотите поддерживать IDN, конечно ... – bobince
Если вы хотите проверить имя существующего хоста, лучше всего попытаться его решить. Вы никогда не будете писать регулярное выражение, чтобы обеспечить такой уровень проверки.
А что, если он хочет узнать, будет ли еще имя хоста, которое еще не существует, будет юридическим? RFC представляется довольно простым, поэтому я не понимаю, почему регулярное выражение не будет работать. –
Зависит от того, что вы пытаетесь показать. Если имя не разрешает, то кто знает, что это значит; истинным средствам проверки требуется информация, которую не может иметь регулярное выражение (т. е. доступ к DNS). Легче просто попробовать и обработать неудачу. И когда вы думаете о именах, которые потенциально легальны, но еще нет, единственные люди, которым на самом деле нужно заботиться об этом, - это регистраторы. Все остальные должны оставить эти вещи в коде, который призван иметь подлинный опыт в этой области.Как отмечает JWZ, применение RE превращает проблему в две проблемы. (Ну, в основном ...) –
Я не согласен. есть две отдельные проблемы, и оба являются действительными проблемами: (1) ° утверждать, может ли данная строка служить, технически и правдоподобно, как, например, действительный адрес электронной почты, имя хоста, такие вещи; (2) ° показывают, что данное имя принято или, вероятно, свободно. (1) является чисто синтаксическим соображением. поскольку (2) происходит по сети, существует сомнительное сомнение: хост, который сейчас находится, может быть отключен через секунду, заказ домена, который я заказываю, теперь можно взять, когда приходит моя почта. – flow
Мне нравится тщательность ответа Тима Пицкера, но я предпочитаю выгрузить некоторую логику из регулярных выражений для удобочитаемости. Честно говоря, мне пришлось посмотреть на смысл тех, что есть«детализация нотации». Кроме того, я считаю, что подход с «двойным отрицанием» более очевиден в том смысле, что он ограничивает ответственность регулярного выражения просто нахождением какого-либо недопустимого характера. Мне нравится, что 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("."))
Вам не нужна обратная косая черта в качестве продолжения строки - они неявны в круглых скобках. –
приятно знать. Я удалил их. – kostmo
Это возвращает 'True' для« 1.1.1.1 »(и любое другое все-числовое имя хоста). –
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))
Что это, запутанный питон? Почему магия, возможно, создает regexp атрибут функции? – kaleissin
Это так, что re.compile нужно делать только один раз, а не каждый раз, когда вызывается функция. Вероятно, это имеет значение только в том случае, если вы вызываете эту функцию много раз в секунду. – btubbs
@imbolc +1 для реализации кодирования idna. – itsafire
Вот немного строже версия Tim Pietzcker's answer со следующими улучшениями:
- Ограничение длины имени хоста до 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)
Согласно RFC 3936 (https://tools.ietf.org/html/rfc3696#section-2), только TLD не должен быть числовым, поэтому я бы сказал, что последнее условие должно выглядеть так: 'if re.match (r "\. (\ d +) $", hostname): ' – Minras
Per The Old New Thing, максимальная длина имени 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('.'))
можно утверждать, для приема пустых доменных имен, или нет, в зависимости от своей цели.
Бесплатный ответ @TimPietzcker. Подчеркивание - это действительное имя хоста, двойная тире - обычная для IDN punycode. Номер порта должен быть удален. Это очистка кода.
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)
Названия имен хостов также не должны заканчиваться дефисом. – bobince
Правильно, спасибо. Отредактировал мой ответ. –
Вы неправильно используете 're.match' - помните, что' re.match ("a +", "ab") 'является совпадением, тогда как' re.match ("a + $", "ab") 'is not , Ваша функция также не допускает ни одной точки в конце имени хоста. – AndiDog