Regular Expression – (正则表达式)匹配 IP 地址

在做 Web 开发的时候,我们经常会需要检测 IP 地址的数据合法性,今天就来介绍一下如何用正则表达式来匹配一个合法的IP地址。

IP 地址规则

首先来看看合法的 IP 地址的规则:

  • 任何一个1位数或2位数;
  • 任何一个以1开头的3位数;
  • 任何一个以2开头、第2位数字在0~4之间的3位数;
  • 任何一个以25开头、第3位数在0~5之间的3位数;

简单点说,IP 地址的每组数字都是 0~255 之间的。例如:

// 合法的 IP 地址
127.0.0.1

// 不合法的 IP 地址
301.22.232.22

下面我们来看看如何一步步的实现对 IP 地址的匹配规则。

第一步:匹配数字

正则表达式中可用使用 \d 来表示任意一个数字,当然也可以使用字符集合区间 [0-9] 或者 [0123456789] 来表示任意一个数字(使用字符集合区间推荐使用 [0-9])。在匹配IP地址这个规则中我们使用 \d 表示数字

第二步:重复匹配

\d 只能表示一个数字,如果需要匹配更多的数字,我们就需要使用几种特殊的元字符来处理了。

匹配一个或多个字符

正则表达式中元字符 + 可以用来匹配一个或多个字符。\d+ 就表示匹配至少一个数字。

匹配零个或多个字符

正则表达式中元字符 * 可以用来匹配零个或多个字符。\d* 就表示匹配任意多个数字。

匹配零个或一个字符

正则表达式中元字符 ? 可以用来匹配零个或一个字符。\d? 就表示匹配零个或一个数字。

IP 地址的每组数字是长度为 1~3 个数字,看来无论是元字符 +* 或者 ? 都无法满足我们的需求,有没有什么办法可以精确匹配重复个数的方法呢?

为重复匹配次数设定区间

在正则表达式中 {} 可以用来为重复匹配设定一个区间,规则如下:

{2} // 精确值,表示字符长度为2;

{2,5} // 区间值,表示最少出现2次,最多出现5次({0,1} 就直接使用 ?)

{3,} // 最小值,表示最少出现3次

IP 地址的重复匹配就应该是:

\d{1,3}

IP 地址会由4组这样的数字链接 “.” 组成,那么应该是这样的:

\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}

第四步:使用子表达式

\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} 细心的朋友会发现,\d{1,3}\. 这段表达式重复出现了3次,正则表达式中是否可以表示某个规则的重复匹配规则呢?

答案是肯定的,正则表达式中可以通过子表达式结合重复匹配的方式来实现。不过在运用这个规则之前,让我们先来了解一下什么是子表达式。

子表达式是一个更大的表达式的一部分;把一个表达式划分为一系列子表达式的目的是为了把那些子表达式当作一个独立元素来使用。子表达式必须使用(和)扩起来。

看完子表达式的介绍,再回到 IP 地址的问题,我们就可以把重复出现的部分作为子表达式:(\d{1,3}\.),然后将这个子表达式作为独立的元素给它添加精确的重复匹配数值3:(\d{1,3}\.){3}

最后我们的 IP 地址的正则表达式可以简化为:(\d{1,3}\.){3}\d{1,3}。我们使用 JavaScript 做一个测试:

let ipAddress = /(\d{1,3}\.){3}\d{1,3}/;

ipAddress.test('192.168.1.1'); // true
ipAddress.test('666.666.666.666'); // true

ipAddress.test('666.666.666.666'); 返回的结果也是 true,很显然 666.666.666.666 并不是一个合法的 IP 地址。因为 IP 地址的最大数值是 255。

第五步:子表达式的嵌套

\d{1,3} 只是一个笼统的规则,表示1~3位的数字,而 IP 地址的规则和很具体,我们需要细化使用4个不同的子表达式来对应一个规则,然后使用子表达式嵌套应用到最终的解决方案中。

规则1:任何一个1位数或2位数

这个规则很简单,就是长度是1~2位(准确的说应该还是0~99之间的任意)的数字,只需要使用\d结合重复匹配的区间就行了,所以规则1的子表达式就是:(\d{1.2})

但是,这么写也会有点问题,就是会出现01~09这样的组合,而这么写是不正确的,所以我们还要细化一下:((\d)|([1-9]\d))

规则2:任何一个以1开头的3位数

这个规则也很容易实现,第一个数字是1就不用说了,然后它是3位数,除去第一个数字1,后面的就是一个任意的两位数:\d{2}(\d表示数字,{2}表明重复两次)。那么以1开头的3位数得子表达式就是:(1\d{2})

规则3:任何一个以2开头、第2位数字在0~4之间的3位数

这个规则其实跟规则2很相似,只是第一个数字是2,后面的2位数对数字的取值范围有了具体的要求:第2位数字在0~4之间。这个规则需要使用前面提到的字符集合区间

字符集区间

为了让大家完全的掌握 IP 地址的匹配过程,在这里我们就简单的介绍一下字符集区间:以[开始,以]结尾,[和]包含的是需要比配的字符。例如:

[ABCDEFGHIJKLMNOPQRSTUVWXYZ] // 大写的 A-Z 字符

[a-z] // 小写的 a-z 之间的字符

[0-9] // 任意一个数字

[A-Za-z0-9] // 任意的英文字母和数字

字符集区间([])表示的是在这个区间内任意的一个字符,可以包含多个字符区间例如:[A-Za-z0-9],字符区间之间直接连接,没有空格。

区间的首字符一定要小于尾字符,[9-1]是没有意义,甚至让整个表达式失效。

-(连接符)只有在字符集区间([和])中使用的时候才是表示区间的元字符,在其他地方使用的时候只是一个字符只能匹配-(连接符)本身,而不是字符集区间中连续的多个字符。如果要在字符集区间中使用-(连接符),则必须使用”\”转义:[\-]。

回到 IP 规则3中的要求:0~4 之间的(1个)数字,使用字符集区间就应该是:[0-4],所以完整的规则3的子表达式就是:(2[0-4]\d)(一个3位数,以2开头,第二个数字在0~4之间,第3个数字任意)。

规则4:任何一个以25开头、第3位数在0~5之间的3位数

规则4可以沿用规则3的写法,只是前两位数都已经确定了是25,而最后一个数的字符区间在0~5之间,所以我们可以很快的得到规则4的子表达式的结果:(25[0-5]\d)

最后的结果

最后来总结一下,将这4个规则的子表达式替换之前的表达式(\d{1,3}\.){3}得到的结果是:(((\d)|([1-9]\d)|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3},这样前3个数字和“.”(点)的表达式就搞定了,而第4个数字跟前面3个数字的规则一样,所以只需要在前3个数字和点后在添加一个数字的规则就行了,也就是:

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

最后使用 JavaScript 来实现,应该是这样的:

// 判断是否为IP
let isIP = /^(((\d)|([1-9]\d)|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d)|([1-9]\d)|(1\d{2})|(2[0-4]\d)|(25[0-5]))$/;
// 匹配所有的IP
let matchIP = /(((\d)|([1-9]\d)|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d)|([1-9]\d)|(1\d{2})|(2[0-4]\d)|(25[0-5]))/g;

看上去一个很简单的 IP 地址的匹配,正则表达式需要掌握的很多知识都涉及到了:匹配数字、字符集区间、子表达式、子表达式嵌套、重复匹配。

关于 IP 地址的匹配就这么多了,希望对正在学习正则表达式的朋友有所帮助。

SHARE THIS PAGE

免责声明:本站文章中的观点都是作者个人观点,并没有以任何方式反映他所属机构的意见。

发表评论