Java中无法用单个正则通过String.matches()完美匹配所有合法IPv4/IPv6,推荐分两步校验:先判断含":"走IPv6正则,否则走IPv4正则;高可靠性场景应使用InetAddress.getByName()最终解析。

Java 的 String.matches() 无法直接用单个正则“完美”匹配所有合法 IPv4 和 IPv6(含压缩格式、IPv4 映射等),因为 IPv6 正则本身复杂,且 matches() 要求**全字符串匹配**,而标准正则引擎(Java 默认的 `java.util.regex`)不支持条件分支或递归,难以兼顾简洁性与完备性。但可以编写一个**实用、覆盖绝大多数常见场景**的正则方案,兼顾可读性与校验强度。
✅ 推荐方案:分两步校验(清晰 + 可靠)
不强行塞进一个正则,而是先粗筛类型,再分别验证:
- 若字符串含
:(且不含.或.出现在:之后),走 IPv6 校验 - 否则走 IPv4 校验
- 两者都用
matches()配合精心设计的正则
示例代码:
public static boolean isValidIp(String ip) {
if (ip == null || ip.trim().isEmpty()) return false;
String s = ip.trim();
if (s.indexOf(':') >= 0) {
// IPv6:支持 ::, 常见压缩,128bit,允许嵌入 IPv4(如 ::ffff:192.0.2.1)
return s.matches(
// 基础 IPv6(8组16进制,可含::压缩) + 可选嵌入IPv4
"^((?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|" + // 8组全写
"([0-9a-fA-F]{1,4}:){1,7}:|" + // :: 开头(1–7组+::)
"([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" + // :: 中间(1–6组 + : + 1组)
"([0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|" + // :: 中间两段
"([0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|" + // :: 中间三段
"([0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|" + // :: 中间四段
"([0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|" + // :: 中间五段
"[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|" + // :: 中间六段
":((?::[0-9a-fA-F]{1,4}){1,7}|:)|" + // :: 结尾 或 ::
// 嵌入 IPv4 场景(如 ::ffff:127.0.0.1)
"(?:[0-9a-fA-F]{1,4}:){1,4}:[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$"
);
} else {
// IPv4:精确 4 段,每段 0–255,无前导零(除单独 0)
return s.matches(
"^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}" +
"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$"
);
}
}
⚠️ 注意事项(避免踩坑)
-
IPv6 正则不校验语义合法性:例如
::1::语法上可能被部分正则误判为合法,但实际非法;上述正则已规避典型错误,但仍建议生产环境用InetAddress.getByName()做最终解析(见下文) -
IPv4 正则禁止前导零:如
192.168.01.1不通过,符合 RFC 规范(01不是合法十进制整数) -
空格必须提前 trim:
matches()不忽略首尾空格,未 trim 会导致失败 -
不支持 IPv6 zone ID(如
fe80::1%eth0):如需支持,需额外剥离%...后缀再校验
? 更健壮的替代方案(推荐用于关键业务)
正则适合快速初筛,但终极校验应交由 JDK 自带的网络层:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
public static boolean isValidIpStrict(String ip) {
if (ip == null || ip.trim().isEmpty()) return false;
try {
InetAddress.getByName(ip.trim());
return true;
} catch (UnknownHostException e) {
return false;
}
}
✔ 优点:100% 符合 RFC、支持所有合法格式(IPv4/IPv6/zone ID/嵌入式)、无需维护正则
⚠ 缺点:有极小性能开销(DNS 查找不触发,仅解析),且在某些安全受限环境(如禁用 DNS)下可能抛 SecurityException
? 总结
用 String.matches() 写“一个正则通吃 IPv4/IPv6”不现实也不推荐。务实做法是:类型分流 + 分别正则校验,兼顾效率与可读;对可靠性要求高的场景,直接委托 InetAddress.getByName() —— 它才是 Java 中 IP 格式校验的权威实现。

















