如果语言支持 PCRE (PHP) 引擎,您可以使用以下正则表达式。请注意,它使用子例程。
(?=(25[0-5]|2[1-4]\d|1\d{2}|[1-9]\d|[1-9])){0}(?=((?1)(?:\.(?1)){3})){0}(?=(?2)(?:,(?2))*$)(?2)
Demo
正则表达式执行以下操作。
定义捕获组 1
(?= # begin positive lookahead
( # begin capture group 1
25[0-5] # match 250-255
| # or
2[0-4]\d # match 200-249
| # or
1\d{2} # match 100-199
| # or
[1-9]\d # match 10-99
| # or
[1-9] # match 1-9
) # end capture group 1
) # end positive lookahead
{0} # execute postive lookahead zero times
定义捕获组 2
(?= # begin positive lookahead
( # begin cap grp 2
(?1) # execute cap grp 1 instructions
(?: # begin non-cap grp
\.(?1) # match '.' then execute cap grp 1 instructions
{3} # end non-cap grp
) # end cap grp 2
) # end positive lookahead
{0} # execute postive lookahead zero times
确认字符串仅包含逗号分隔的有效 IPv4 地址
(?= # begin positive lookahead
(?2) # execute cap grp 2 instructions
(?: # begin non-cap grp
,(?2) # match ',' then execute cap grp 2 instructions
) # end non-cap grp
* # execute non-cap grp 0+ times
$ # match end of line
) # end positive lookahead
匹配 IPv4 地址
(?2) # execute cap grp 2 instructions
一些支持子例程(或子表达式)的正则表达式引擎可能具有不同的语法。例如,Ruby 使用\g<1> 而不是(?1)。也可以使用命名的捕获组。 PCRE 将(?P>sue) 用于名为“sue”的捕获组。详情请见this discussion。
如果不想使用子例程,或者语言的正则表达式引擎不支持它们(我理解 Python 就是其中之一),可以用捕获组 1 的内容替换,例如 (?1):
25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|[1-9]
自然,正则表达式的大小会大大增加(考虑替换(?2))。使用子程序的另一个好处是每个子程序都可以单独测试。
非正则表达式方法
我认为开发上述正则表达式是一种练习(也是向一些读者介绍正则表达式子例程的机会),但我不建议采用这种方法来支持使用普通语言工具。例如,在 Ruby 中,只需要几行代码,如下所示。那些不熟悉 Ruby 的人应该能够了解代码中发生的事情的要点。
require 'ipaddr'
def ipv4s(str)
str.split(',').map do |s|
i = IPAddr.new(s)
raise ArgumentError, "'#{s}' is not an IP address" if i.nil?
raise ArgumentError, "'#{s}' is not an IPv4 address" unless i.ipv4?
s
end
end
ipv4s("172.24.64.100,172.25.64.100,172.26.64.100")
#=> "2001:0DB8:AC10:FE01:0000:0000:0000:0000"
ipv4s("172.24.64.100, 172.25.64.100,172.26.64.100")
#=> IPAddr::InvalidAddressError ( 172.25.64.100)
^
ipv4s("172.2403.64.100,172.25.64.100,172.26.64.100")
#=> IPAddr::InvalidAddressError (72.2403.64.100)
^^^^
ipv4s("cat 172.24.64.100,172.25.64.100,172.26.64.100")
#=> IPAddr::InvalidAddressError (cat 172.24.64.100)
^^^^
ipv4s("172.24.64.100,172.25.64.275,172.26.64.100")
#=> IPAddr::InvalidAddressError (172.25.64.275)
^^^