Java提取字符串中的IP地址

在本文中,我们学习了如何从Java 中的字符串中提取 IP 地址。使用正则表达式,我们创建了一个检测有效 IPv4 地址的模式。然后,基于正则表达式模式,我们实施了一个解决方案来捕获给定字符串中的每个 IP。

在处理日志文件或分析网络流量数据时,我们经常需要从 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 matcher = IP_PATTERN.matcher(input);
    List<String> result = new ArrayList<>();
    while (matcher.find()) {
        result.add(matcher.group());
    }
    return result;
}

该方法非常简单。使用 matcher.find(),我们迭代字符串,将每个匹配项收集到预先初始化的ArrayList中。 每次调用find()时,  matcher.group()都会返回匹配的子字符串(IP 地址),我们将其添加到结果列表中。

接下来,让我们创建一些测试数据来验证我们的方法是否按预期工作:

首先,如果字符串 不包含任何 IP 地址,我们期望得到一个空列表:

static final String INPUT1 = "No IP address here";
static final List<String> EXPECTED1 = Collections.emptyList();

当字符串包含单个 IP 地址时,结果列表应包含预期的 IP 地址:

static final String INPUT2 = "My local ip is 127.0.0.1";
static final List<String> EXPECTED2 = List.of(
"127.0.0.1");
 
static final String INPUT3 =
"Another ip address is 192.168.42.42";
static final List<String> EXPECTED3 = List.of(
"192.168.42.42");

如上所述,每个八位字节应介于 0 到 255 之间,因此我们应该只提取有效部分:

static final String INPUT4 = "Extract the valid part: 260.1.2.345";
static final List<String> EXPECTED4 = List.of(
"60.1.2.34");

如果输入中没有有效的 IP 地址,结果应该为空:

static final String INPUT5 = "No valid ip address 260.42.342.345";
static final List<String> EXPECTED5 = Collections.emptyList();

当然,如果输入包含多个 IP 地址,我们应该获取所有 IP 地址:

static final String INPUT6 = "We have multiple ip addresses: 127.1.1.0, 192.168.42.42 and 245.30.1.34";
static final List<String> EXPECTED6 = List.of(
"127.1.1.0", "192.168.42.42", "245.30.1.34");


最后,让我们使用这些输入来测试我们的方法:

assertEquals(EXPECTED1, extractIP(INPUT1));
assertEquals(EXPECTED2, extractIP(INPUT2));
assertEquals(EXPECTED3, extractIP(INPUT3));
assertEquals(EXPECTED4, extractIP(INPUT4));
assertEquals(EXPECTED5, extractIP(INPUT5));
assertEquals(EXPECTED6, extractIP(INPUT6));

当我们运行测试时,它通过了。因此,该方法解决了问题。