使用正则表达式匹配文本中的所有 IP 地址

Match all IP addresses in text with regex

假设我有一个字符串,其中可能包含一个或多个 IP 地址。如何在 ruby?

中使用正则表达式匹配所有且仅匹配有效的

目前,我的解决方案如下所示:

IP_ADDR_REGEX = %r{
  \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
}x

这在 IP 以空格分隔时效果很好,例如它从文本 bla bla 192.168.1.1 bla 中提取 192.168.1.1。但是在这种情况下它仍然提取 192.168.1.1bla bla 192.168.1.1.1.1 bla

如何让它不匹配这种情况?即当它是 192.168.1.1.1.1 时,我的正则表达式不应该 return 匹配。我已经寻找了很多关于这个问题的解决方案,但找不到我想要的。我也试图通过最后只匹配空格来自己找出解决方案(因为 \b 也匹配 . 字符)但我无法使其工作。 谢谢

您应该将单词边界匹配器 \b 更改为显式 space(并使用正前瞻匹配它,因为您不希望它被返回):

IP_ADDR_REGEX = %r{
  (?<=\s|^)
  (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]?)
  (?=\s|$)
}x

main ▶ 'bla bla 192.168.1.1.1.1 bla'[IP_ADDR_REGEX]
#⇒ nil
main ▶ 'bla bla 192.168.1.1.1 bla'[IP_ADDR_REGEX]
#⇒ nil
main ▶ 'bla bla 192.168.1.1 bla'[IP_ADDR_REGEX]
#⇒ "192.168.1.1"

如果类 IP 字符串前面有一个数字和一个点,或者后面有一个点和一个数字,您可以通过添加将使匹配失败的环视来解决此问题:

IP_ADDR_REGEX = %r{
  \b                                        # Word boundary
  (?<!\d\.)                                 # Negative lookbehind: no "X." before
  (?: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                                        # Word boundary
  (?!\.\d)                                  # Negative lookahead: no ".X" after
}x

Regex demo #1

请注意,如果您只想将匹配限制为以空格分隔的子字符串,请使用

IP_ADDR_REGEX = %r{
  (?<!\S)                                    # Position not preceded with non-whitespace char
  (?: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]?)
  (?!\S)                                    # Position not followed with non-whitespace char
}x

Regex demo #2

请注意,(?:...) 非捕获组可以更轻松地使用 String#scan 方法从字符串中收集所有匹配项。