IP地址或CIDR块匹配正则表达式

5

我需要检查一个字符串是否符合IPv4地址或者以下CIDR块之一:/16或/24。 因此,192.168.0.1应该匹配。 192.168.0.0/16应该匹配。 192.168.0.0/17不应该匹配。 我使用以下正则表达式:

re.compile(r'^([0-9]{1,3}\.){3}[0-9]{1,3}(/(16|24))?')

这个正则表达式匹配所有的IP地址,但也会匹配像192.168.0.0/aaaa这样的字符串。

现在,如果我改变正则表达式(去掉结尾的?):

re.compile(r'^([0-9]{1,3}\.){3}[0-9]{1,3}(/(16|24))')

它可以匹配CIDR块/16或/24,但不再匹配IP地址(例如,192.168.0.1)。

问号不应该检查组的可选出现吗?我做错了什么?

注意:我知道IP地址正则表达式本身并不完美,但我更希望在描述的问题上得到帮助。

4个回答

15

这应该可以工作:

^([0-9]{1,3}\.){3}[0-9]{1,3}($|/(16|24))$

它检查 $行结束)或 /,以及 1624

就像你所说的那样,? 标记将一个组标记为可选项,这意味着如果可能的话它将尝试将其包含在匹配中。但在某些情况下,比如 192.168.0.0/aaaa,由于它是可选的,它仍然会匹配其他部分。

这就是为什么上面的正则表达式更适合您的需求。通过这种方式,只有在它以/24/16行结尾结尾时才能匹配,例如192.168.0.1


1
上述正则表达式有效,但也匹配形如“192.168.0.0/16ddddd”的字符串。我需要这个正则表达式进行验证,因此我在可选模式的末尾添加了$:r'^([0-9]{1,3}.){3}[0-9]{1,3}($|/(16|24)$)'。 - tigeronk2
我想要匹配任何CIDR块16-32,所以我使用了这个正则表达式: /^([0-9]{1,3}.){3}[0-9]{1,3}($|/([1][6-9]|[2][0-9]|[3][0-2]))$/^和$也有助于修剪字符串前后的任何内容。主要区别在于第三个捕获组中匹配16到32之间的任何数字,如下所示: [1][6-9]|[2][0-9]|[3][0-2] - undefined

4

精确匹配

匹配 0.0.0.0255.255.255.255。如果指定了CIDR块,则仅在CIDR为1624时匹配。 示例:

^                                                 # Start string
(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.               # A in A.B.C.D
(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.               # B in A.B.C.D
(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.               # C in A.B.C.D
(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)($|/(16|24))?    # D in A.B.C.D and /16 or /24
$                                                 # End string

1

你有什么理由觉得必须使用单个正则表达式来处理这个问题吗?这真的是一个钉子(*)吗?你不能安装并使用Python IPAddr模块来解析和操作你的IP地址吗?我猜你可以像这样做:

#!/usr/bin/env python
import ipaddr
...
mynet = ipaddr.IPv4Network('192.168.0.0/16')
try:
    other = ipaddr.IPv4Network(other_network_string)
    nm = other.netmask
except ipaddr.AddressValueError:
    other = None
    nm = None

...

if nm and nm == mynet.netnmask:
    be_happy()

换句话说,有一个包,其中有人已经完成了解析和操作IP地址字符串的所有繁重工作。你真的想为你的代码重新做多少工作?你想花多少时间测试你的新代码,并找到这个包的创建者可能已经发现和修复的相同类型的错误?
如果我听起来像是在强调这一点...那是因为这种方法似乎与使用正则表达式解析HTML(或XML)而不是使用已经编写好的现有、经过测试、健壮的解析器完全相似。
(如果手头唯一的工具是锤子,每个问题看起来都像钉子)

我正在使用正则表达式进行表单输入验证。您认为我在表单验证中也应该使用ipaddr吗?我确实在另一个模块中使用ipaddr,用于实际根据存储的列表验证传入请求的IP。 - tigeronk2
我会使用它,而不是尝试编写自己的解析器/验证器。理想情况下,这将使您的代码具备未来性,以便在IPv6或其他表示网络的替代方式被开发出来时轻松支持。正如我所说,该模块的维护者已经遇到并修复了一些您不太可能想到的边角情况,除非您编写一个正式的词法解析器。 - Jim Dennis

0

'?'的语义有点复杂(只是一点点)。你可以把它想象成副词“可能”的同义词。
它的工作方式是:如果有一个子字符串与我的模式匹配,那么就继续进行匹配过程。我用“IF”和“THEN”突出了这一点,因为蕴含的语义表明,如果前提不满足,整个句子仍然是真的。

因此,现在让我们将这个原则应用到你的情况上。你在后缀上放了一个“?”。假设前面的部分匹配,现在让我们处理后缀:如果有一个后缀与你的模式匹配,整个字符串就会匹配。如果后缀不匹配,也没有问题:带有“?”标记的块是“可选的”(记住“可能”的语义或等价的蕴含语义),因此字符串仍然匹配。

因此,在模式的最后部分放置一个“?”块并不是很有用,因为无论是否有匹配的后缀,字符串仍然会匹配。可选块只在字符串中间有用。


谢谢您对“?”的解释。但是,我也期望能得到解决方法。 - tigeronk2

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