首先我们知道IPV4的范围是 0.0.0.0 - 255.255.255.255,那么我们需要对0到255范围的数字进行分段匹配:
1. 匹配0-9之间的数 [0-9] 或 \d
2. 匹配10-99之间的数 [1-9][0-9] 或 [1-9]\d
3. 匹配100-199之间的数 1[0-9][0-9] 或 1\d{2}
4. 匹配200-249之间的数 2[0-4][0-9] 或 2[0-4]\d
5. 匹配250-255之间的数 25[0-5]
以上是数字的匹配,我们还需要匹配英文小数点 \.
注意 0-199 之间那几个正则是不是有相似之处? 那我们还可以在进一步优化为[01]?\d?\d 或者[01]?\d{1,2}。
(扩展一下:像0-X999 类似范围的正则表达式都可以 [0-X]\d{1,N}这样来表示。X范围是1-9, N为9的个数,比如此例中N为3)
好了综合一下,即匹配IPV4的正则表达式为(?:(?:[01]?\d?\d|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d?\d|2[0-4]\d|25[0-5])
注意这里带\b和不带\b的区别
#!/usr/bin/perl
my $ipv4_reg = qr<\b(?:(?:(?:[01]?\d?\d|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d?\d|2[0-4]\d|25[0-5]))\b>;
#my $ipv4_reg = qr<(?:(?:[01]?\d?\d|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d?\d|2[0-4]\d|25[0-5])>;
while (<DATA>)
{
chomp;
if (/($ipv4_reg)/)
{
print $1,"\n";
}
else
{
print $_." is invalid ip\n" ;
}
}
__DATA__
1.1.1.1
1111.1.1.1
a111.1.1.1
1 111.1.1.1
a 111.1.1.1
如果匹配一行中有个IP的情况,最好是写一个函数来实现。先提取类似IP的数字出来,然后判断该数字是否为IP。
其实还有一些特殊情况,要看需求来定正则表达式。比如:1.5.4.3.1,用\b来做锚定符的话,可以匹配出5.4.3.1,这时应该是no match才对。这时候就需要在$ipv4_reg两头加上锚点(?<!\.)和(?!\.)
(?<!\.)$ipv4_reg(?!\.)
总之,特殊情况还需特殊对待。
实在觉得麻烦,还能去cpan中去找模块去解决问题。比如Net::IP::Match::Regexp
其实解析IP地址,还可以先用正则匹配出一段string,然后交给socket库中inet_pton函数的去判断是否是ip。