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

Validating IPv4 addresses with regexp

我一直在尝试获得一个有效的用于IPv4验证的regex,但运气不太好。在某一点上,我似乎和(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?(\.|$)){4}有过这种关系,但它产生了一些奇怪的结果:

1
2
3
4
5
6
7
8
9
$ 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

我做了一个搜索,看看这个问题是否已经被问过和回答过,但其他的答案似乎只是显示如何确定4组1-3的数字,或者不适合我。


你已经得到了一个有效的答案,但是为了防止你好奇你原来的方法有什么问题,答案是你需要在你的替代品周围加上括号,否则只有当数字小于200时,才需要(\.|$)

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


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

接受:

1
2
3
4
5
6
127.0.0.1
192.168.1.1
192.168.1.255
255.255.255.255
0.0.0.0
1.1.1.01

拒绝:

1
2
3
4
5
30.168.1.255.1
127.1
192.168.1.256
-1.2.3.4
3...3

在线尝试单元测试:https://www.debuggex.com/r/-edzoqxtxhitncn6/1


regex不是此作业的工具。最好编写一个解析器来分隔这四个数字,并检查它们是否在[0255]范围内。非功能regex已无法读取!


新的和改进的较短版本

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

它使用负前瞻性(?!)来消除IP可能以.结尾的情况。

旧答案

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

我认为这是最准确和最严格的regex,它不接受像000.021.01.0.这样的问题。这里的大多数答案似乎都是这样的,需要额外的regex来拒绝类似的情况,即0起始数字和以.结尾的IP。


IPv4地址(准确捕获)匹配0.0.0.0到255.255.255.255使用此regex以精确匹配IP号码。这4个数字中的每一个都存储在一个捕获组中,因此您可以访问它们进行进一步的处理。

1
2
3
4
5
6
\b
(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-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.
(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
\b

摘自JGSoft RegexBuddy图书馆

编辑:这个(\.|$)部分看起来很像


我在寻找类似于ipv4地址的东西——一个regex,它也阻止了常用的私有IP地址被验证(192.168.x.y,10.x.y.z,172.16.x.y),所以使用了否定的外观a heads来完成这一点:

1
2
3
(?!(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.).*)
(?!255\.255\.255\.255)(25[0-5]|2[0-4]\d|[1]\d\d|[1-9]\d|[1-9])
(\.(25[0-5]|2[0-4]\d|[1]\d\d|[1-9]\d|\d)){3}

(当然,这些应该放在一行上,为便于阅读而格式化,放在3行上)Regular expression visualization

调试程序演示

它可能不会优化速度,但只在寻找"真实"的互联网地址时工作得很好。

会(也应该)失败的事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0.1.2.3         (0.0.0.0/8 is reserved for some broadcasts)
10.1.2.3        (10.0.0.0/8 is considered private)
172.16.1.2      (172.16.0.0/12 is considered private)
172.31.1.2      (same as previous, but near the end of that range)
192.168.1.2     (192.168.0.0/16 is considered private)
255.255.255.255 (reserved broadcast is not an IP)
.2.3.4
1.2.3.
1.2.3.256
1.2.256.4
1.256.3.4
256.2.3.4
1.2.3.4.5
1..3.4

将(并且应该)工作的IP:

1
2
3
4
5
6
1.0.1.0         (China)
8.8.8.8         (Google DNS in USA)
100.1.2.3       (USA)
172.15.1.2      (USA)
172.32.1.2      (USA)
192.167.1.2     (Italy)

如果其他人正在验证"不包括公用专用地址的Internet IP地址"


我认为许多阅读本文的人会寻找更简单的正则表达式,即使它们匹配一些技术上无效的IP地址。(而且,正如其他地方提到的,regex可能不是正确验证IP地址的正确工具。)

如果不想匹配行首/行尾,则删除^,并在适用的情况下用\b替换$

基本正则表达式(BRE)(在gnu grep、gnu sed和vim上测试):

1
/^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$/

扩展正则表达式(ERE):

1
/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/

或:

1
/^([0-9]+(\.|$)){4}/

Perl兼容正则表达式(PCRE)(在Perl 5.18上测试):

1
/^\d+\.\d+\.\d+\.\d+$/

或:

1
/^(\d+(\.|$)){4}/

Ruby(在Ruby 2.1上测试):

虽然应该是PCRE,但是Ruby出于任何原因允许Perl5.18不允许使用这个regex:

1
/^(\d+[\.$]){4}/

我对所有这些的测试都是在线的。


这比某些服务器稍长,但这是我用来匹配IPv4地址的。简单而不妥协。

1
^((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])$

上面的答案是有效的,但是如果IP地址不在行尾,并且在文本之间怎么办?这个regex甚至可以解决这个问题。

代码:'\b((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.)){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\b'

输入文本文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
ip address 0.0.0.0 asfasf
 sad sa 255.255.255.255 cvjnzx
zxckjzbxk  999.999.999.999 jshbczxcbx
sjaasbfj 192.168.0.1 asdkjaksb
oyo 123241.24121.1234.3423 yo
yo 0000.0000.0000.0000 y
aw1a.21asd2.21ad.21d2
yo 254.254.254.254 y0
172.24.1.210 asfjas
200.200.200.200
000.000.000.000
007.08.09.210
010.10.30.110

输出文本:

1
2
3
4
5
6
0.0.0.0
255.255.255.255
192.168.0.1
254.254.254.254
172.24.1.210
200.200.200.200


1
(((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开头的任何三位数,如果第二位数是0的话。通过4

  • 25开头的任何三位数,如果第三位数是0的话。通过5

让我们从一组由四个嵌套子表达式组成的(((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)通过249匹配数字200(25[0-5])通过255匹配数字250。这些子表达式中的每一个子表达式都包含在另一个子表达式中,每个子表达式之间都有一个|(这样四个子表达式中的一个子表达式必须匹配,而不是全部匹配)。在数字范围之后,\..匹配,然后将整个系列(所有数字选项加上\.)封装到另一个子表达式中,并使用{3}重复三次。最后,重复数字范围(这次没有尾随的\.)以匹配最终的IP地址号。通过将这四个数字中的每一个都限制在0255之间的值,这种模式确实可以匹配有效的IP地址并拒绝无效的地址。

Excerpt From: Ben Forta."Learning Regular Expressions."

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

1
^(((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


带子网掩码:

1
2
3
4
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])
((/([01]?\\d\\d?|2[0-4]\\d|25[0-5]))?)$

’’这段代码对我很有用,而且非常简单。

在这里,我取了ip的值,并尝试将其与regex匹配。

1
2
3
4
5
6
7
8
9
10
11
ip="25.255.45.67"    

op=re.match('(\d+).(\d+).(\d+).(\d+)',ip)

if ((int(op.group(1))<=255) and (int(op.group(2))<=255) and int(op.group(3))<=255) and (int(op.group(4))<=255)):

print("valid ip")

else:

print("Not valid")

上述条件检查所有4个八位字节的值是否超过255,则该值无效。但是在应用条件之前,我们必须将它们转换为整数,因为值在字符串中。

组(0)打印匹配的输出,而组(1)打印第一个匹配的值,这里是"25",依此类推。’’


我设法从所有其他答案构造了一个正则表达式。

1
(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}

1
2
3
4
    const char*ipv4_regexp ="\\b(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-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
   "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b";

我将jgsoft regexbuddy库中的正则表达式改编为C语言(regcomp/regexec),发现它可以工作,但在一些操作系统(如Linux)中有点问题。该正则表达式接受类似192.168.100.009的IPv4地址,其中Linux中的009被视为一个八进制值,因此该地址不是您认为的地址。我把正则表达式改为:

1
2
3
4
    const char* ipv4_regex ="\\b(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])\\."
          "(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])\\b";

现在使用常规表达式192.168.100.009不是有效的IPv4地址,而192.168.100.9是正常的。

我也修改了多播地址的正则表达式,它是:

1
2
3
4
    const char* mcast_ipv4_regex ="\\b(22[4-9]|23[0-9])\\."
                       "(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]?)\\."
                       "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\b";

我认为您必须使正则表达式适应开发应用程序所使用的语言。

我在Java中举了一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    package utility;

    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    public class NetworkUtility {

        private static String ipv4RegExp ="\\b(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d?)\\b";

        private static String ipv4MulticastRegExp ="2(?:2[4-9]|3\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d?|0)){3}";

        public NetworkUtility() {

        }

        public static boolean isIpv4Address(String address) {
            Pattern pattern = Pattern.compile(ipv4RegExp);
            Matcher matcher = pattern.matcher(address);

            return matcher.matches();
        }

        public static boolean isIpv4MulticastAddress(String address) {
             Pattern pattern = Pattern.compile(ipv4MulticastRegExp);
             Matcher matcher = pattern.matcher(address);

             return matcher.matches();
        }
    }


1
2
3
-bash-3.2$ echo"191.191.191.39" | egrep
  '(^|[^0-9])((2([6-9]|5[0-5]?|[0-4][0-9]?)?|1([0-9][0-9]?)?|[3-9][0-9]?|0)\.{3}
     (2([6-9]|5[0-5]?|[0-4][0-9]?)?|1([0-9][0-9]?)?|[3-9][0-9]?|0)($|[^0-9])'

>> 191.191.191.39

(这是一个与整个地址空间(包括广播等)匹配的DFA,而不是别的。


我觉得这个最短。

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

我发现这个示例非常有用,而且它允许不同的IPv4符号。

使用python的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    def is_valid_ipv4(ip4):
   """Validates IPv4 addresses.
   """
    import re
    pattern = re.compile(r"""
        ^
        (?:
          # Dotted variants:
          (?:
            # Decimal 1-255 (no leading 0's)
            [3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
          |
            0x0*[0-9a-f]{1,2}  # Hexadecimal 0x0 - 0xFF (possible leading 0's)
          |
            0+[1-3]?[0-7]{0,2} # Octal 0 - 0377 (possible leading 0's)
          )
          (?:                  # Repeat 0-3 times, separated by a dot
            \.
            (?:
              [3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
            |
              0x0*[0-9a-f]{1,2}
            |
              0+[1-3]?[0-7]{0,2}
            )
          ){0,3}
        |
          0x0*[0-9a-f]{1,8}    # Hexadecimal notation, 0x0 - 0xffffffff
        |
          0+[0-3]?[0-7]{0,10}  # Octal notation, 0 - 037777777777
        |
          # Decimal notation, 1-4294967295:
          429496729[0-5]|42949672[0-8]\d|4294967[01]\d\d|429496[0-6]\d{3}|
          42949[0-5]\d{4}|4294[0-8]\d{5}|429[0-3]\d{6}|42[0-8]\d{7}|
          4[01]\d{8}|[1-3]\d{0,9}|[4-9]\d{0,8}
        )
        $
   """, re.VERBOSE | re.IGNORECASE)
    return pattern.match(ip4) <> None

找到有效的IP地址,只要IP被包裹在除数字以外的任何字符(IP后面或前面)。创建了4个反向引用:$+第一个.$+第二个.$+第三个.$+第四个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Find String:
#any valid IP address
(?<IP>(?<![\d])(?<first>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<second>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<third>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<forth>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))(?![\d]))
#only valid private IP address RFC1918
(?<IP>(?<![\d])(:?(:?(?<first>10)[\.](?<second>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5])))|(:?(?<first>172)[\.](?<second>(:?1[6-9])|(:?2[0-9])|(:?3[0-1])))|(:?(?<first>192)[\.](?<second>168)))[\.](?<third>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<forth>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))(?![\d]))

Notepad++ Replace String Option 1: Replaces the whole IP (NO Change):
$+{IP}

Notepad++ Replace String Option 2: Replaces the whole IP octect by octect (NO Change)
$+{first}.$+{second}.$+{third}.$+{forth}

Notepad++ Replace String Option 3: Replaces the whole IP octect by octect (replace 3rd octect value with 0)
$+{first}.$+{second}.0.$+{forth}
NOTE: The above will match any valid IP including 255.255.255.255 for example and change it to 255.255.0.255 which is wrong and not very useful of course.

用实际值替换每个octect的一部分,但是您可以创建自己的查找和替换,这对文本文件中的ammond ips实际有用:

1
2
3
4
5
6
7
8
9
10
11
12
13
for example replace the first octect group of the original Find regex above:
(?<first>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))
with
(?<first>10)

and
(?<second>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))
with
(?<second>216)
and you are now matching addresses starting with first octect 192 only

Find on notepad++:
(?<IP>(?<![\d])(?<first>10)[\.](?<second>216)[\.](?<third>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<forth>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))(?![\d]))

您仍然可以使用与以前完全相同的back referece组执行替换。

您可以了解上面的匹配方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
cat ipv4_validation_test.txt
Full Match:
0.0.0.1
12.108.1.34
192.168.1.1
10.249.24.212
10.216.1.212
192.168.1.255
255.255.255.255
0.0.0.0


Partial Match (IP Extraction from line)
30.168.1.0.1
-1.2.3.4
sfds10.216.24.23kgfd
da11.15.112.255adfdsfds
sfds10.216.24.23kgfd


NO Match
1.1.1.01
3...3
127.1.
192.168.1..
192.168.1.256
da11.15.112.2554adfdsfds
da311.15.112.255adfdsfds

使用grep,您可以看到以下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
From grep:
grep -oP '(?<IP>(?<![\d])(?<first>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<second>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<third>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<forth>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))(?![\d]))' ipv4_validation_test.txt
0.0.0.1
12.108.1.34
192.168.1.1
10.249.24.212
10.216.1.212
192.168.1.255
255.255.255.255
0.0.0.0
30.168.1.0
1.2.3.4
10.216.24.23
11.15.112.255
10.216.24.23


grep -P '(?<IP>(?<![\d])(?<first>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<second>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<third>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<forth>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))(?![\d]))' ipv4_validation_test.txt
0.0.0.1
12.108.1.34
192.168.1.1
10.249.24.212
10.216.1.212
192.168.1.255
255.255.255.255
0.0.0.0
30.168.1.0.1
-1.2.3.4
sfds10.216.24.23kgfd
da11.15.112.255adfdsfds
sfds10.216.24.23kgfd


#matching ip addresses starting with 10.216
grep -oP '(?<IP>(?<![\d])(?<first>10)[\.](?<second>216)[\.](?<third>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))[\.](?<forth>(:?\d)|(:?[1-9]\d)|(:?1\d{2})|(:?2[0-4]\d)|(:?25[0-5]))(?![\d]))' ipv4_validation_test.txt
10.216.1.212
10.216.24.23
10.216.24.23

这一个只匹配有效的IP(没有预先准备好的0,但是它将匹配0-255的八位字节,不管它们的"函数"(即保留、私有等)),并允许内联匹配,在IP之前和/或之后可能有空格,或者使用CIDR符号时。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)'

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< '10.0.1.2'
10.0.1.2

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< 'ip address 10.0.1.2'
ip address 10.0.1.2

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< 'ip address 10.0.1.2 255.255.255.255'
ip address 10.0.1.2 255.255.255.255

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< 'ip address 10.0.1.2/32'
ip address 10.0.1.2/32

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< 'ip address 10.0.1.2.32'
$

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< 'ip address10.0.1.2'
$

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< '10.0.1.256'
$

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< '0.0.0.0'
0.0.0.0

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< '255.255.255.255'
255.255.255.255

$ grep -E '(^| )((([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($| |/)' <<< '255.255.255.256'
$

当然,在IP是内联的情况下,如果只需要整个IP,而只需要IP,那么可以使用grep选项"-o"和您对空白修剪器的偏好。

对于我们使用python的人来说,等价物大致是:

1
2
3
>>> ipv4_regex = re.compile(r'(^| )((?:[1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:[1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])($| |/)')
>>> ipv4_regex.search('ip address 10.1.2.3/32')
<re.Match object; span=(10, 20), match=' 10.1.2.3/'>

如果你像我一样挑剔,你可能更喜欢使用分组来获取整个IP,而不是IP。在我们不关心空间/开始/结束的情况下(我想大多数情况下),我们可以使用(?:)使space/begin/end paren设置为非捕获的语法,因此我们可以使用group(1)访问IP,而只访问IP。

1
2
3
4
5
>>> ipv4_regex = re.compile(r'(?:^| )(((?:[1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:[1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]))(?:$| |/)')
>>> ipv4_regex.search('ip address 10.0.1.2/32')
<re.Match object; span=(10, 20), match=' 10.0.1.2/'>
>>> ipv4_regex.search('ip address 10.0.1.2/32').group(1)
'10.0.1.2'

当然,有很多方法不只是使用regex。这里有一些您可以检查的条件(这个条件没有找到inline,只是验证传递的地址是否有效)。

首先检查地址中的每个字符是一个数字或一个''。

下一步检查是否正好有3''

接下来的两个检查检查每个八位字节是否在0到255之间。

最后一个检查是没有用"0"开头的八位字节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def validate_ipv4_address(address):
    return all(re.match('\.|\d', c) for c in address) \
        and address.count('.') == 3 \
        and all(0 <= int(octet) <= 255 for octet in address.split('.')) \
        and all((len(bin(int(octet))) <= 10 for octet in address.split('.'))) \
        and all(len(octet) == 1 or d[0] != '0' for octet in address.split('.'))


>>> validate_ipv4_address('255.255.255.255')
True
>>> validate_ipv4_address('10.0.0.1')
True
>>> validate_ipv4_address('01.01.01.01')
False
>>> validate_ipv4_address('123.456.789.0')
False
>>> validate_ipv4_address('0.0.0.0')
True
>>> validate_ipv4_address('-1.0.0.0')
False
>>> validate_ipv4_address('1.1.1.')
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
  File"<stdin>", line 4, in validate_ipv4_address
  File"<stdin>", line 4, in <genexpr>
ValueError: invalid literal for int() with base 10: ''
>>> validate_ipv4_address('.1.1.1')
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
  File"<stdin>", line 4, in validate_ipv4_address
  File"<stdin>", line 4, in <genexpr>
ValueError: invalid literal for int() with base 10: ''
>>> validate_ipv4_address('1..1.1')
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
  File"<stdin>", line 4, in validate_ipv4_address
  File"<stdin>", line 4, in <genexpr>
ValueError: invalid literal for int() with base 10: ''

(按位排列,每个八位字节应小于或等于8位,但每个八位字节前面都有'0b')

1
2
3
4
5
6
7
8
>>> bin(0)
'0b0'
>>> len(bin(0))
3
>>> bin(255)
'0b11111111'
>>> len(bin(256))
11


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

上面是IP地址的regex,如:221.23 4.000 0.112也适用于221.234.0.112、221.24.03.112、221.234.0.1

你可以想象上面的各种地址


我会使用pcre和define关键字:

1
2
3
4
5
/^
 ((?&byte))\.((?&byte))\.((?&byte))\.((?&byte))$
 (?(DEFINE)
     (?<byte>25[0-5]|2[0-4]\d|[01]?\d\d?))
/gmx

演示:https://regex101.com/r/ib7j48/2

这样做的原因是为了避免重复四次(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)模式。其他解决方案(如下面的解决方案)工作得很好,但并没有像许多人要求的那样捕获每个组。

1
/^((\d+?)(\.|$)){4}/

拥有4个捕获组的唯一其他方法是将模式重复四次:

1
/^(?<one>\d+)\.(?<two>\d+)\.(?<three>\d+)\.(?<four>\d+)$/

因此,在Perl中捕获IPv4非常容易

1
2
3
4
5
6
7
8
$ echo"Hey this is my IP address 138.131.254.8, bye!" | \
  perl -ne 'print"[$1, $2, $3, $4]" if \
    /\b((?&byte))\.((?&byte))\.((?&byte))\.((?&byte))
     (?(DEFINE)
        \b(?<byte>25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))
    /x'

[138, 131, 254, 8]

我能想象的最精确、最直接和最紧凑的IPv4 regexp是

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

但是……的性能/效率呢?对不起,我不知道,谁在乎?


试试这个:

1
\b(([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-5][0-5])\.([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-5][0-5])\.([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-5][0-5])\.(2[0-5][0-5]|1[0-9][0-9]|[1-9][0-9]|[1-9]))\b

1
2
3
4
5
6
7
8
9
10
ip address can be from 0.0.0.0 to 255.255.255.255

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

(0|1)?[0-9][0-9]? - checking value from 0 to 199
2[0-4][0-9]- checking value from 200 to 249
25[0-5]- checking value from 250 to 255
[.] --> represent verify . character
{3} --> will match exactly 3
$ --> end of string


下面是用于验证IP地址的regex表达式。

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

简易方法

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

演示


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

此regex将不接受08.8.8.8或8.08.8.8或8.8.08.8或8.8.8.08


这是我的Regex工厂:"\<((([1-9]|1[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([1-9]|1[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))\>"


IPv4地址是一件非常复杂的事情。

注:压痕和衬里仅用于说明目的,不存在于真正的regex中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
\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地址由上述regex验证。

1
2
3
4
5
6
7
8
9
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

这些都被拒绝了。

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

1
2
3
4
5
6
7
String zeroTo255 ="([0-9]|[0-9][0-9]|(0|1)[0-9][0-9]|2[0-4][0-9]|25[0-5])";

it can contain single digit i.e ([0-9]);  
It can contain two digits i.e ([0-9][0-9]);
range is (099 to 199)i.e((0|1)[0-9][0-9]);
range is (200 - 249) i.e (2[0-9][0-9]) ;
range is (250-255) i.e(25[0-5]);

1
mysql> select ip from foo where ip regexp '^\\s*[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]\\s*';