代码之家  ›  专栏  ›  技术社区  ›  kostmo

验证主机名字符串

  •  23
  • kostmo  · 技术社区  · 14 年前

    后续行动 Regular expression to match hostname or IP Address? 并使用 Restrictions on valid host names 作为参考,在python中,匹配/验证hostname/fqdn(完全限定域名)最可读、最简洁的方法是什么?我已经用下面的尝试回答了,欢迎改进。

    9 回复  |  直到 5 年前
        1
  •  43
  •   Olli    11 年前
    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 结束于 . ,也没关系。如果 主机名 以多个点结尾。

        2
  •  4
  •   Community Mofi    7 年前

    这里有一个更严格的版本 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)
    
        3
  •  3
  •   solidsnack    9 年前

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

    人们可以根据自己的目的,争论是否接受空域名。

        4
  •  1
  •   kostmo    14 年前

    我喜欢tim pietzcker完整的回答,但是为了可读性,我更喜欢从正则表达式中卸载一些逻辑。老实说,我得查一下 (? “扩展符号”部分。另外,我觉得“双重否定”方法更明显,因为它将正则表达式的责任限制为只查找任何无效字符。我真的很喜欢。ignorecase允许regex被缩短。

    这是另一张照片,它更长,但读起来有点像散文。我想“可读的”和“简洁的”有点矛盾。我相信到目前为止线程中提到的所有验证约束都包括在内:

    
    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
  •  1
  •   mootmoot    5 年前

    感谢@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 )
    
        6
  •  0
  •   imbolc    13 年前
    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))
    
        7
  •  0
  •   Steve Goossens    6 年前

    此纯正则表达式应满足所有参数: ^(?=.{1,253}\.?$)(?!-)[A-Za-z0-9\-]{1,63}(\.[A-Za-z0-9\-]{1,63})*\.?(?<!-)$

        8
  •  -1
  •   kostmo    14 年前

    通过排除无效字符并确保非零长度,分别处理每个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
  •  -4
  •   Donal Fellows    14 年前

    如果要验证现有主机的名称,最好的方法是尝试解析它。您永远不会编写正则表达式来提供该级别的验证。