Python 验证主机名字符串

Python 验证主机名字符串,python,regex,validation,hostname,fqdn,Python,Regex,Validation,Hostname,Fqdn,后续行动 作为参考,在Python中匹配/验证主机名/fqdn(完全限定域名)的最可读、最简洁的方法是什么?我已经回答了下面的问题,欢迎改进。通过排除无效字符并确保长度不为零,分别处理每个DNS标签 def isValidHostname(hostname): disallowed = re.compile("[^a-zA-Z\d\-]") return all(map(lambda x: len(x) and not disallowed.search(x), hostnam

后续行动
作为参考,在Python中匹配/验证主机名/fqdn(完全限定域名)的最可读、最简洁的方法是什么?我已经回答了下面的问题,欢迎改进。

通过排除无效字符并确保长度不为零,分别处理每个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(".")))
重新导入
def是有效的主机名(主机名):
如果len(主机名)>255:
返回错误
如果主机名[-1]==”:
hostname=hostname[:-1]#如果有,从右边正好去掉一个点

allowed=re.compile((?!-)[A-Z\d-]{1,63}(?如果您希望验证现有主机的名称,最好的方法是尝试解析它。您永远不会编写一个正则表达式来提供那种级别的验证。

我喜欢Tim Pietzcker的答案的彻底性,但我更愿意为了可读性而从正则表达式中去掉一些逻辑。老实说,我必须查找这些
(?
“扩展符号”部分的含义。此外,我觉得“双重否定”方法更为明显,因为它将正则表达式的责任限制为仅查找任何无效字符。我喜欢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("."))

def isValidHostname(主机名):
如果len(主机名)>255:
返回错误
如果hostname.endswith(“.”):#单个尾随点是合法的
hostname=hostname[:-1]#如果有,从右边正好去掉一个点
disallowed=re.compile(“[^A-Z\d-]”,re.IGNORECASE)
返回所有(#按标签分割并单独验证

(label和len(label)这里有一个更严格的版本,有以下改进:

  • 将主机名的长度限制为253个字符(去掉可选的尾随点后)
  • 将字符集限制为ASCII(即使用
    [0-9]
    而不是
    \d
  • 检查TLD是否全部为数字
重新导入
def是有效的主机名(主机名):
如果主机名[-1]==”:
#如果存在,则从右侧正好去掉一个点
主机名=主机名[:-1]
如果len(主机名)>253:
返回错误
labels=hostname.split(“.”)
#TLD不能全部为数字
如果重新匹配(r“[0-9]+$”,则标签[-1]):
返回错误
allowed=re.compile(r)(?!-)[a-z0-9-]{1,63}(?Per,DNS名称的最大长度为253个字符。(一个最多允许255个八位字节,但其中2个八位字节被编码占用。)

重新导入
def验证_fqdn(dn):
如果dn.endswith('.'):
dn=dn[:-1]
如果len(dn)<1或len(dn)>253:
返回错误
ldh_re=re.compile(“^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?”,
关于(不知情情况)
返回dn.split('.')中x的所有(ldh匹配(x))

人们可能会争论是否接受空域名,这取决于一个人的目的。

对@TimPietzcker答案的补充。 是有效的主机名字符(但不适用于域名)。而双破折号通常用于IDN punycode域(例如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_hostname(normalise_host )
重新导入
def是有效的主机名(主机名):
如果len(主机名)>255:
返回错误
hostname=hostname.rstrip(“.”)

allowed=re.compile((?!-)[A-Z\d\-\\\\\\\\\\\\\{1,63}(?我认为这个正则表达式在Python中可能有帮助:
“^([a-zA-Z0-9]+(\.\124; \-)*[a-zA-Z0-9]+$”

不要重新发明轮子。您可以使用库,例如验证程序。或者您可以复制:

装置 用法
返回全部(x且不被禁止。在主机名中搜索(x)x。拆分(“.”)
主机名末尾的尾随
是有效的。哦,如果您想支持IDN,当然还有很多工作要做……主机名标签也不应该以连字符结尾。您使用的
re.match
不正确-请注意
re.match(“A+”,“ab”)
是一个匹配,而
re.match(“a+$,“ab”)
不是。您的函数也不允许在主机名的末尾有一个点。我一直认为
re.match
需要匹配整个字符串,因此不需要字符串的结尾锚定。但我现在发现(谢谢!)它只将匹配项绑定到字符串的开头。我相应地更正了我的正则表达式。但是,我不明白你的第二点。将主机名结尾为点合法吗?问题中链接的维基百科文章似乎说不合法。@Tim Pietzcker是的,结尾只有一个点是合法的。它将该名称标记为完全限定的域名,这使得DNS系统知道它不应该尝试将本地域附加到其中。请注意,每个段也有63个字符的限制。整个主机名有一个255个字符的全局限制。如果他想知道一个还不存在的主机名是否是合法的,该怎么办?RFC看起来很简单,所以我不明白为什么要使用正则表达式不起作用。取决于您试图显示的内容。如果名称没有解析,那么谁知道它的“含义”;真正的验证方法需要正则表达式无法拥有的信息(即访问DNS)。尝试并处理失败会更容易。当考虑到可能合法但尚未合法的名称时,真正需要关心的人只有注册者。其他人都应该将这些事情留给在该领域拥有真正专业知识的代码。正如JWZ所指出的,应用RE会带来问题分为两个问题。(嗯,大部分…)我不同意。有两个独立的问题,两个都是有效的问题:(1)°论证给定字符串在技术上是否可以作为,比如,有效的电子邮件地址、主机名等;(2)°证明
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))
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)
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('.'))
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_hostname(normalise_host )
pip install validators
import validators
if validators.domain('example.com')
    print('this domain is valid')