使用正则表达式验证IPv4地址

206

我一直在尝试获得一个高效的IPv4验证正则表达式,但是运气不太好。有一段时间似乎我已经通过 (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?(\.|$)){4} 得到了正确结果,但它产生了一些奇怪的结果:

$ grep --version
grep (GNU grep) 2.7
$ grep -E '\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?(\.|$)){4}\b' <<< 192.168.1.1
192.168.1.1
$ grep -E '\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?(\.|$)){4}\b' <<< 192.168.1.255
192.168.1.255
$ grep -E '\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?(\.|$)){4}\b' <<< 192.168.255.255
$ grep -E '\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?(\.|$)){4}\b' <<< 192.168.1.2555
192.168.1.2555

我搜索过,看是否已经有人问过并得到了回答,但其他答案似乎仅展示如何确定由1-3个数字组成的4组数字,或者对我没有用。


22
别忘了 A、A.B 和 A.B.C 也是有效的 IP 地址格式,不只是 A.B.C.D。真的,请尝试用“ping 2130706433”和“ping 127.1”,可以让你发笑。 - dty
1
我的变量在线 https://regexr.com/39hqf - Enginer
47个回答

4

这是一个比较长的匹配IPv4地址的方法,非常简单而且没有任何妥协。

^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$

4

我从其他答案中构建了一个正则表达式。

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

根据IEEE 802.x以太网标准,IP验证如下: IP范围0.x.x.x >>> 不应被允许 - 无效的IP。 #1.IP范围从1.x.x.x到126.x.x.x >>>> 可以被允许配置。 #2.IP范围127.x.x.x >>>> 不应被允许 - 无效的IP。 #3.IP范围128.x.x.x到223.x.x.x >> 可以被允许配置。 更好的处理方式建议如下: ^(22[0-3]|2[0-1][0-9]|[1][0-9][0-9]?|[1-9][0-9]|[1-9]).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-4]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ - Yogesh Aggarwal

4

对于0到255之间的数字,我使用以下正则表达式:

(([0-9])|([1-9][0-9])|(1([0-9]{2}))|(2[0-4][0-9])|(25[0-5]))

上述正则表达式将匹配从0到255之间的整数,但不匹配256。
因此,对于IPv4,我使用以下正则表达式:
^(([0-9])|([1-9][0-9])|(1([0-9]{2}))|(2[0-4][0-9])|(25[0-5]))((\.(([0-9])|([1-9][0-9])|(1([0-9]{2}))|(2[0-4][0-9])|(25[0-5]))){3})$

这个结构是:^(N)((\.(N)){3})$,其中 N 是用于匹配从0到255的数字的正则表达式。
这个正则表达式将匹配以下格式的IP地址:

0.0.0.0
192.168.1.2

但不包括以下内容:
10.1.0.256
1.2.3.
127.0.1-2.3

对于IPv4 CIDR(无类域间路由选择)我使用这个正则表达式:

^(([0-9])|([1-9][0-9])|(1([0-9]{2}))|(2[0-4][0-9])|(25[0-5]))((\.(([0-9])|([1-9][0-9])|(1([0-9]{2}))|(2[0-4][0-9])|(25[0-5]))){3})\/(([0-9])|([12][0-9])|(3[0-2]))$

这个表达式的结构是:^(N)((\.(N)){3})\/M$ 其中 N 是用于匹配 0 到 255 范围内的数字的正则表达式,而 M 是用于匹配 0 到 32 范围内的数字的正则表达式。
此正则表达式将匹配以下 CIDR:

0.0.0.0/0
192.168.1.2/32

但不包括下面这些:
10.1.0.256/16
1.2.3./24
127.0.0.1/33

对于类似于"10.0.0.0/16", "192.168.1.1/32"的IPv4 CIDR列表,我使用以下正则表达式:

^("(([0-9])|([1-9][0-9])|(1([0-9]{2}))|(2[0-4][0-9])|(25[0-5]))((\.(([0-9])|([1-9][0-9])|(1([0-9]{2}))|(2[0-4][0-9])|(25[0-5]))){3})\/(([0-9])|([12][0-9])|(3[0-2]))")((,([ ]*)("(([0-9])|([1-9][0-9])|(1([0-9]{2}))|(2[0-4][0-9])|(25[0-5]))((\.(([0-9])|([1-9][0-9])|(1([0-9]{2}))|(2[0-4][0-9])|(25[0-5]))){3})\/(([0-9])|([12][0-9])|(3[0-2]))"))*)$

正则表达式如下所示:^(“C”)((,([ ]*)(“C”))*)$ 其中 C 是用于匹配 CIDR(如0.0.0.0/0)的正则表达式。
此正则表达式将匹配以下CIDR列表:

10.0.0.0/16”,”192.168.1.2/32”, “1.2.3.4/32

但不包括以下内容:
“10.0.0.0/16” 192.168.1.2/32 “1.2.3.4/32”

也许它可能会变短,但对我来说很容易理解,所以对我来说没问题。
希望这有帮助!

欢迎来到SO,我们感谢您的贡献!您能否详细说明一下不同的正则表达式是如何工作的(特别是最后一个)? - B--rian

3
IPv4地址是一件非常复杂的事情。
注意:缩进和对齐仅供说明目的,在真正的正则表达式中不存在。
\b(
  ((
    (2(5[0-5]|[0-4][0-9])|1[0-9]{2}|[1-9]?[0-9])
  |
    0[Xx]0*[0-9A-Fa-f]{1,2}
  |
    0+[1-3]?[0-9]{1,2}
  )\.){1,3}
  (
    (2(5[0-5]|[0-4][0-9])|1[0-9]{2}|[1-9]?[0-9])
  |
    0[Xx]0*[0-9A-Fa-f]{1,2}
  |
    0+[1-3]?[0-9]{1,2}
  )
|
  (
    [1-3][0-9]{1,9}
  |
    [1-9][0-9]{,8}
  |
    (4([0-1][0-9]{8}
      |2([0-8][0-9]{7}
        |9([0-3][0-9]{6}
          |4([0-8][0-9]{5}
            |9([0-5][0-9]{4}
              |6([0-6][0-9]{3}
                |7([0-1][0-9]{2}
                  |2([0-8][0-9]{1}
                    |9([0-5]
    ))))))))))
  )
|
  0[Xx]0*[0-9A-Fa-f]{1,8}
|
  0+[1-3]?[0-7]{,10}
)\b

这些IPv4地址已经通过上述正则表达式验证。
127.0.0.1
2130706433
0x7F000001
017700000001
0x7F.0.0.01 # Mixed hex/dec/oct
000000000017700000001 # Have as many leading zeros as you want
0x0000000000007F000001 # Same as above
127.1
127.0.1

这些被拒绝了。

256.0.0.1
192.168.1.099 # 099 is not a valid number
4294967296 # UINT32_MAX + 1
0x100000000
020000000000

好的,谢谢。 - huh-hulk

3

在文本中找到一个有效的IP地址是一个非常困难的问题


我有一个正则表达式,可以从文本文件中的字符串中匹配(提取)有效的IP地址。

我的正则表达式

\b(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){2}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\b
  • \b - 单词边界
  • (?: - 开始非捕获组
  • ^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])\.) - 字符串必须以第一个正确的八位数和点字符开头
    • (?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|\code>[1-9]) - 找到第一个正确的八位数(第一个八位数不能以0开头)
  • (?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){2} - 找到下一个正确的两个八位数和点字符串
  • (?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\b - 字符串必须以正确的第四个八位数结尾(现在允许零字符)

但是,这个IP正则表达式有少量错误匹配:

https://regexr.com/69dk7

regexp for mostly right match for ip addresses

仅通过正则表达式查找或提取文本文件中的有效IP地址是不可能的。如果不检查其他条件,您将始终获得错误的匹配。

解决方案


我编写了一行Perl代码来从文本文件中提取IP地址。它具有以下条件:

  • 当IP地址位于行开头时,下一个字符是一个或多个空格字符(空格、制表符、换行符等)
  • 当IP地址在行末时,新行是下一个字符,在IP地址之前是一个或多个空格字符
  • 在文本中间 - IP地址之前和之后都是一个或多个空格字符

结果是Perl不会匹配像https://84.25.74.125和另外一些URI字符串这样的字符串。或以点字符结尾的行末IP地址。但它可以找到文本中的任何有效IP地址。

perl one liner解决方案:

$ cat ip.txt | perl -lane 'use warnings; use strict; for my $i (@F){if ($i =~/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){2}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/) { print $i; } }'
36.42.84.233
158.22.45.0
36.84.84.233
12.0.5.4
1.25.45.36
255.3.6.5
4.255.2.1
127.0.0.1
127.0.0.5
126.0.0.1

测试文本文件:

$ cat ip.txt
36.42.84.233 stop 158.22.45.0 and 56.32.58.2.
25.36.84.84abc and abc2.4.8.2 is error.
1.2.3.4_
But false positive is 2.2.2.2.2.2.2.2 or 1.1.1.1.1
http://23.54.212.1:80
https://89.35.248.1/abc
36.84.84.233 was 25.36.58.4/abc/xyz&158.133.26.4&another_var
and 42.27.0.1:8333 in http://212.158.45.2:26
0.25.14.15 ip can not start with zero
2.3.0
abc 12.0.5.4
1.25.45.36
12.05.2.5
256.1.2.5
255.3.6.5
4.255.2.1
4.256.5.6
127.0.0.1 is localhost.
this ip 127.0.0.5 is not localhost
126.0.0.1

附录


对于来自其他星球的人来说,2130706433127.124.005.04.52 这些字符串是有效的IP地址,我有一条信息要告诉你们:试着自己找到解决方案!!!


注:IP地址是指互联网协议地址,用于给计算机设备在网络中进行定位和通信。

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

测试寻找文本中的匹配项,https://regex101.com/r/9CcMEN/2

以下是每个IP地址号码中定义有效组合的规则:

  • 任何一位或两位数字。
  • 任何以1开头的三位数。

  • 任何以2开头且第二位数字为04的三位数。

  • 任何以25开头且第三位数字为05的三位数。

让我们从 (((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2}))\.) 开始,这是一组四个嵌套的子表达式,我们将逆序查看它们。 (\d{1,2}) 匹配任何一位或两位数字或数字099(1\d{2}) 匹配任何以1开头的三位数字(1后面跟着任意两位数字),或数字100199(2[0-4]\d) 匹配数字200249(25[0-5]) 匹配数字250255。每个子表达式都被包含在另一个子表达式中,并在每个子表达式之间使用|(因此必须匹配四个子表达式中的一个,而不是全部)。在数字范围之后是\.以匹配.,然后将整个系列(所有数字选项加上\.)再次包装到另一个子表达式中,并使用{3}重复三次。最后,重复数字范围(这次没有尾随\.),以匹配最终的IP地址号码。通过将每个数字限制在0255之间的值,此模式确实可以匹配有效的IP地址并拒绝无效地址。

摘自:Ben Forta. “Learning Regular Expressions.”


如果IP地址开头或结尾都不需要字符,应分别使用^$元字符。

^(((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2}))\.){3}(((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2})))$

寻找文本中的匹配项测试, https://regex101.com/r/uAP31A/1


2
最短的模式未必是最高效的。我更喜欢。
^(?:\b\.?(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){4}$

这是模式长度和效率之间的一个很好的折中。
这个模式通过使用\b单词边界和使点可选来工作。单词边界仍然要求每个0-255之间有一个点。将\b放置在^开头处禁止了点的出现。
当然,使用(捕获)而不是(?:非捕获)可以节省四个字符,但为什么要无缘无故地捕获任何内容呢?没有任何部分会被重复使用或提取。
唯一有意义的原因是,如果不支持非捕获组
不验证0-255并允许任意一个到三个数字:^(?:\b\.?\d{1,3}){4}$

2

考虑到一些提出的变量,\d\b可能不被支持。因此,为了以防万一:

IPv4地址

^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)$

测试:https://debuggex.com/r/izHiog3KkYztRMSJ

图表


2

Java中IPV4地址的有效正则表达式

^((\\d|[1-9]\\d|[0-1]\\d{2}|2[0-4]\\d|25[0-5])[\\.]){3}(\\d|[1-9]\\d|[0-1]\\d{2}|2[0-4]\\d|25[0-5])$

我尝试了这篇文章中的一些方法,但是没有一个能通过代码信号测试,但是这个可以。谢谢! - M.Islam

1
带有子网掩码的:

^$|([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\
.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\
.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\
.([01]?\\d\\d?|2[0-4]\\d|25[0-5])
((/([01]?\\d\\d?|2[0-4]\\d|25[0-5]))?)$

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