2010-03-28 4 views
21

После Regular expression to match hostname or IP Address? и используя Restrictions on valid host names в качестве ссылки, что является наиболее читаемым, сжатым способом сопоставления/проверки имени хоста/fqdn (полное доменное имя) в Python? Я ответил с моей попыткой ниже, улучшения приветствуются.Подтвердить строку имени хоста

ответ

39
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 заканчивается более чем одной точкой.

+1

Названия имен хостов также не должны заканчиваться дефисом. – bobince

+0

Правильно, спасибо. Отредактировал мой ответ. –

+0

Вы неправильно используете 're.match' - помните, что' re.match ("a +", "ab") 'является совпадением, тогда как' re.match ("a + $", "ab") 'is not , Ваша функция также не допускает ни одной точки в конце имени хоста. – AndiDog

-1

Обработать каждую метку 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("."))) 
+2

'возврата всех (х, а не disallowed.search (х) при х в hostname.split (""))' – 2010-03-28 06:44:01

+1

трейлинг '.' на конце имени хоста является действительным. О, и многое другое нужно сделать, если вы хотите поддерживать IDN, конечно ... – bobince

-4

Если вы хотите проверить имя существующего хоста, лучше всего попытаться его решить. Вы никогда не будете писать регулярное выражение, чтобы обеспечить такой уровень проверки.

+4

А что, если он хочет узнать, будет ли еще имя хоста, которое еще не существует, будет юридическим? RFC представляется довольно простым, поэтому я не понимаю, почему регулярное выражение не будет работать. –

+0

Зависит от того, что вы пытаетесь показать. Если имя не разрешает, то кто знает, что это значит; истинным средствам проверки требуется информация, которую не может иметь регулярное выражение (т. е. доступ к DNS). Легче просто попробовать и обработать неудачу. И когда вы думаете о именах, которые потенциально легальны, но еще нет, единственные люди, которым на самом деле нужно заботиться об этом, - это регистраторы. Все остальные должны оставить эти вещи в коде, который призван иметь подлинный опыт в этой области.Как отмечает JWZ, применение RE превращает проблему в две проблемы. (Ну, в основном ...) –

+0

Я не согласен. есть две отдельные проблемы, и оба являются действительными проблемами: (1) ° утверждать, может ли данная строка служить, технически и правдоподобно, как, например, действительный адрес электронной почты, имя хоста, такие вещи; (2) ° показывают, что данное имя принято или, вероятно, свободно. (1) является чисто синтаксическим соображением. поскольку (2) происходит по сети, существует сомнительное сомнение: хост, который сейчас находится, может быть отключен через секунду, заказ домена, который я заказываю, теперь можно взять, когда приходит моя почта. – flow

1

Мне нравится тщательность ответа Тима Пицкера, но я предпочитаю выгрузить некоторую логику из регулярных выражений для удобочитаемости. Честно говоря, мне пришлось посмотреть на смысл тех, что есть«детализация нотации». Кроме того, я считаю, что подход с «двойным отрицанием» более очевиден в том смысле, что он ограничивает ответственность регулярного выражения просто нахождением какого-либо недопустимого характера. Мне нравится, что 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(".")) 
+0

Вам не нужна обратная косая черта в качестве продолжения строки - они неявны в круглых скобках. –

+0

приятно знать. Я удалил их. – kostmo

+0

Это возвращает 'True' для« 1.1.1.1 »(и любое другое все-числовое имя хоста). –

0
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)) 
+4

Что это, запутанный питон? Почему магия, возможно, создает regexp атрибут функции? – kaleissin

+0

Это так, что re.compile нужно делать только один раз, а не каждый раз, когда вызывается функция. Вероятно, это имеет значение только в том случае, если вы вызываете эту функцию много раз в секунду. – btubbs

+0

@imbolc +1 для реализации кодирования idna. – itsafire

3

Вот немного строже версия 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) 
+1

Согласно RFC 3936 (https://tools.ietf.org/html/rfc3696#section-2), только TLD не должен быть числовым, поэтому я бы сказал, что последнее условие должно выглядеть так: 'if re.match (r "\. (\ d +) $", hostname): ' – Minras

3

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('.')) 

можно утверждать, для приема пустых доменных имен, или нет, в зависимости от своей цели.

0

Бесплатный ответ @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) 

 Смежные вопросы

  • Нет связанных вопросов^_^