正则表达式匹配DNS主机名或IP地址?

409

有没有一个正则表达式能匹配任何合法的DNS主机名或IP地址?

编写一个能够在95%的情况下工作的正则表达式很容易,但我希望得到一个经过充分测试以精确匹配最新RFC规范的DNS主机名的表达式。


1
请注意:可以确定一个字符串是否是有效的IPv4地址或有效的主机名,但不能确定一个字符串既是有效的IPv4地址又是有效的主机名。原因是:任何匹配为有效IPv4地址的字符串也可能是有效的主机名,可以通过DNS服务器解析为不同的IP地址。 - ndsvw
22个回答

1
新的网络框架为IPv4Address结构体和IPv6Address结构体提供了可失败的初始化程序,可以轻松处理IP地址部分。使用正则表达式在IPv6中进行此操作是困难的,因为所有缩短规则都需要考虑。
不幸的是,我没有一个优雅的答案来处理主机名。
请注意,Network框架是最近的,因此可能会强制您编译最近的操作系统版本。
import Network
let tests = ["192.168.4.4","fkjhwojfw","192.168.4.4.4","2620:3","2620::33"]

for test in tests {
    if let _ = IPv4Address(test) {
        debugPrint("\(test) is valid ipv4 address")
    } else if let _ = IPv6Address(test) {
        debugPrint("\(test) is valid ipv6 address")
    } else {
        debugPrint("\(test) is not a valid IP address")
    }
}

output:
"192.168.4.4 is valid ipv4 address"
"fkjhwojfw is not a valid IP address"
"192.168.4.4.4 is not a valid IP address"
"2620:3 is not a valid IP address"
"2620::33 is valid ipv6 address"

1
/^(?:[a-zA-Z0-9]+|[a-zA-Z0-9][-a-zA-Z0-9]+[a-zA-Z0-9])(?:\.[a-zA-Z0-9]+|[a-zA-Z0-9][-a-zA-Z0-9]+[a-zA-Z0-9])?$/

0

试一下这个:

((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

在我的情况下它有效。


0

这是一个正则表达式,我在Ant中使用它来从ANT_OPTS中获取代理主机IP或主机名。这是用于获取代理IP以便在为分叉的JVM配置代理之前运行Ant“isreachable”测试。

^.*-Dhttp\.proxyHost=(\w{1,}\.\w{1,}\.\w{1,}\.*\w{0,})\s.*$

那是一个\w,它不会捕获IP,只会在某些情况下捕获主机名。 - Yaron

0

我发现这对于IP地址非常有效。它像顶部答案一样进行验证,但它还确保IP被隔离,因此IP之后或之前没有文本或更多的数字/小数。

(?<!\S)(?:(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\b|.\b){7}(?!\S)


我尝试了很多次,但我无法理解这里的两个问题。1. \b指定单词边界,为什么我们要使用\b?哪个是边界?2. 为什么它只适用于{7}?根据我的理解,应该是{4},但它不起作用。另外,您可以告诉我为什么要使用非捕获块。 - Srichakradhar

0

这里还有一个缺失的微妙之处。

确实,HOSTNAME应该基本上与上面给出的匹配。

缺失的是,对主机名的引用可以相同,加上可选的句点。

例如,使用尾随句点,ping foo.bar.svc.cluster.local.将仅ping该主机名,并且不会尝试在resolv.conf中进行任何DNS搜索选项。

tldr-如果您提供一个输入框来接收主机名,则输入的内容实际上不需要是有效的主机名。


0

0
关于IP地址,似乎存在一些争议,是否应该包括前导零。虽然这曾经是常见做法并且被普遍接受,但我认为它们应该被标记为有效,而不考虑当前的偏好。同时,对于字符串前后的文本是否应该进行验证也存在一些歧义,我认为应该进行验证。1.2.3.4是一个有效的IP地址,但1.2.3.4.5不是,无论是1.2.3.4部分还是2.3.4.5部分都不应该匹配。可以使用以下表达式来解决其中的一些问题:
grep -E '(^|[^[:alnum:]+)(([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])\.){3}([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])([^[:alnum:]]|$)' 

不幸的是,验证八位字节的正则表达式部分在许多提供的解决方案中都是重复的。虽然这比模式实例更好,但如果正则表达式支持子程序,则可以完全消除重复。下一个示例使用grep-P开关启用这些功能,并利用前瞻和后顾功能。(我选择的函数名是'o'表示八位字节。我本可以使用'octet'作为名称,但想要简洁明了。)

grep -P '(?<![\d\w\.])(?<o>([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(\.\g<o>){3}(?![\d\w\.])'

如果IP地址在以句子形式呈现的文本文件中,处理点可能会导致错误的负面结果,因为句号可能跟在点分表示法之后而不是作为其中一部分。以下是上述变体的修复方法:

grep -P '(?<![\d\w\.])(?<x>([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(\.\g<x>){3}(?!([\d\w]|\.\d))'

-1
在php中: filter_var(gethostbyname($dns), FILTER_VALIDATE_IP) == true ? 'ip' : 'not ip'

2
尽管此代码可能回答了问题,但通常在代码旁边提供解释会使答案更有用。请[编辑]您的答案并提供一些上下文和解释。 - Sebastian Simon
1
而且,除非我弄错了,FILTER_VALIDATE_IP 是 PHP 中的一个值。 - DonGar

-1

这个怎么样?

([0-9]{1,3}\.){3}[0-9]{1,3}

而且9999999999.0.0.9999999999也是如此。:) 但对于大多数程序员来说,这种简短的方法就足够了。 - andreas
3
-1是因为它匹配无意义的IP地址(正如@Shebuka所指出的那样)。 - bdesham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接