在处理日志文件或分析网络流量数据时,我们经常需要从 Java 中给定的字符串中提取 IP 地址。
在本教程中,我们将研究IPv4地址的格式,然后使用 Java 的正则表达式(regex) 功能创建解决方案。
关于 IP 地址的几点说明
IPv4 地址由四个八位字节组成,每个八位字节由点分隔,每个八位字节是 0 到 255 之间的数字。这意味着有效的 IPv4 地址如下所示:
0.0.0.0
192.168.0.8
234.223.43.42
255.255.255.0
接下来,我们将制作一个正则表达式模式来识别 IP 地址形式的任何字符序列。然后,我们可以应用此模式从字符串中提取所有 IP 地址。
创建匹配 IP 地址的正则表达式
让我们首先看一下正则表达式,然后了解它为什么匹配 IP 地址:
code[.]){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[/code]
我们在此正则表达式中使用了非捕获组 (?:)。非捕获组对事物进行分组而不创建反向引用。
稍后我们来看一下八位字节模式,以便更轻松地理解正则表达式结构。然后,正则表达式如下所示:
code[.]){3}(?:OCTET_PATTERN)[/code]
此部分匹配前三个 ( {3} ) 个八位字节,后跟一个文字点,最后匹配第四个八位字节。值得一提的是,虽然“.”在正则表达式中表示任何单个字符,但如果我们将其放在字符类“ [.] ”中,它匹配文字点字符。
接下来,我们仔细看看OCTET_PATTERN :
code[/code]
此部分通过组合三种可能性来匹配 0 到 255 之间的任何有效数字。让我们看看这个内部组中的每个选项。
- 25[0-5] – 匹配 250 至 255 之间的数字
- 2[0-4][0-9] – 匹配 200 至 249 之间的数字
- [01]?[0-9][0-9]? – 匹配从 0 到 199 的数字。
现在我们理解了正则表达式,让我们创建一个 Java 方法来从字符串中提取 IP 地址。
创建提取 IP 地址的方法
首先,让我们从讨论过的正则表达式中获取一个 Pattern 实例:
static final Pattern IP_PATTERN = Pattern.compile("(?:(?: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]?)");
由于一个字符串可以包含多个IP 地址,让我们创建一个方法,接受输入并返回一个字符串值列表作为提取的 IP 地址:
List<String> extractIP(String input) { |
该方法非常简单。使用 matcher.find(),我们迭代字符串,将每个匹配项收集到预先初始化的ArrayList中。 每次调用find()时, matcher.group()都会返回匹配的子字符串(IP 地址),我们将其添加到结果列表中。
接下来,让我们创建一些测试数据来验证我们的方法是否按预期工作:
首先,如果字符串 不包含任何 IP 地址,我们期望得到一个空列表:
static final String INPUT1 = "No IP address here"; |
当字符串包含单个 IP 地址时,结果列表应包含预期的 IP 地址:
static final String INPUT2 = "My local ip is 127.0.0.1"; |
如上所述,每个八位字节应介于 0 到 255 之间,因此我们应该只提取有效部分:
static final String INPUT4 = "Extract the valid part: 260.1.2.345"; |
如果输入中没有有效的 IP 地址,结果应该为空:
static final String INPUT5 = "No valid ip address 260.42.342.345"; |
当然,如果输入包含多个 IP 地址,我们应该获取所有 IP 地址:
static final String INPUT6 = "We have multiple ip addresses: 127.1.1.0, 192.168.42.42 and 245.30.1.34"; |
最后,让我们使用这些输入来测试我们的方法:
assertEquals(EXPECTED1, extractIP(INPUT1)); |
当我们运行测试时,它通过了。因此,该方法解决了问题。