【问题标题】:List of IPv4 addresses separated by a comma regex?用逗号正则表达式分隔的 IPv4 地址列表?
【发布时间】:2020-03-26 11:43:24
【问题描述】:

我有一个匹配 IPv4 地址的正则表达式:

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

现在我想要相同的正则表达式,但要使用逗号分隔的 IPv4 地址列表

示例(无法以逗号结束字符串):

172.24.64.100.0,172.25.64.100.0,172.26.64.100 

我该怎么做?

谢谢,

【问题讨论】:

  • 这可能有效^(?:(?: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]?)(?:,(?:(?: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]?))*$
  • 移除锚点(^$),假设<x> 是匹配单个项目的结果。然后<x>(?:,<x>)* 将匹配此类项目的非空序列,<x>(?:,<x>)+ 将匹配具有至少两个项目/一个逗号的此类序列。如果您需要匹配整个字符串而不是部分字符串,请在该正则表达式周围添加锚点
  • @Eraklon 有点长,但它工作得很好,谢谢!
  • @DeadlockState Np。大致思路是(?:<pattern>)(?:,<pattern>)*

标签: regex


【解决方案1】:

如果语言支持 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)
                                             ^^^   


                

【讨论】:

  • 您可以删除您的评论,因为我已经编辑了我的答案来解决这个问题。我建议您编辑您的问题以澄清锚点是必需的。此外,在您的示例中,前两个 IPv4 地址的形式不是 xxx.xxx.xxx.xxx