题目
先来看下题目描述
描述
编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址
IPv4 地址由十进制数和点来表示,每个地址包含4个十进制数,其范围为 0 - 255, 用(“.”)分割。比如,172.16.254.1;
同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。
IPv6 地址由8组16进制的数字来表示,每组表示 16 比特。这些组数字通过 (“:”)分割。比如, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。
然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (:😃 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。
同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。
说明: 你可以认为给定的字符串里没有空格或者其他特殊字符。
解
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 验证IP地址 * @param IP string字符串 一个IP地址字符串 * @return string字符串 */ public String solve (String IP) { // write code here String[] ipv4 = IP.split("\\.",-1); String[] ipv6 = IP.split(":",-1); if (ipv4.length ==4) { if (valid4(ipv4)) { return "IPv4"; } else { return "Neither"; } } if (ipv6.length ==8) { if (valid6(ipv6)) { return "IPv6"; } else { return "Neither"; } } return "Neither"; } private boolean valid4(String[] ipv4) { if (ipv4.length != 4) { return false; } for (int i = 0; i < ipv4.length; i++) { if (ipv4[i].length() > 1 && ipv4[i].startsWith("0")) { return false; } try { int val = Integer.parseInt(ipv4[i]); if (!(val >= 0 && val <= 255)) { return false; } } catch (NumberFormatException numberFormatException) { return false; } } return true; } private boolean valid6(String[] ipv6) { if (ipv6.length != 8) { return false; } for (int i = 0; i < ipv6.length; i++) { if (ipv6[i].length() > 4 || ipv6[i].length() == 0) { return false; } try { int val = Integer.parseInt(ipv6[i], 16); } catch (NumberFormatException numberFormatException) { return false; } } return true; } }
知识点
在这个算法题里,有两个我之前写代码没有注意到的点,第一个是非常常用的split,第二个是string转int的方式,下面一个一个说。
分割字符串
假设这是我们要分割的内容: String IP="2001:0db8:85a3:0:0:8A2E:0370:7334:"
IP.split(":", -1)
和IP.split(":")
在使用上有以下区别:
IP.split(":", -1)
:
- 当第二个参数为负数时,
split()
方法会保留字符串末尾的空字符串元素。 - 在给定的IP地址中,末尾有一个额外的冒号":",如果使用
split(":", -1)
,则会保留末尾的空字符串。 - 结果数组中的最后一个元素会是空字符串,因为冒号":"位于末尾。
IP.split(":")
:
- 当不指定第二个参数或者第二个参数为非负数时,
split()
方法会自动忽略末尾的空字符串元素。 - 在给定的IP地址中,末尾有一个额外的冒号":",如果使用
split(":")
,则会自动忽略末尾的空字符串。 - 结果数组中的最后一个元素不会是空字符串,因为默认情况下,
split()
方法会忽略末尾的空字符串。
下面是一个示例:
public class SplitExample { public static void main(String[] args) { String IP = "2001:0db8:85a3:0:0:8A2E:0370:7334:"; String[] splitArray1 = IP.split(":", -1); String[] splitArray2 = IP.split(":"); System.out.println("Using split(\":\", -1):"); for (String element : splitArray1) { System.out.println("[" + element + "]"); } System.out.println("Using split(\":\"):"); for (String element : splitArray2) { System.out.println("[" + element + "]"); } } }
输出结果:
Using split(":", -1): [2001] [0db8] [85a3] [0] [0] [8A2E] [0370] [7334] [] Using split(":"): [2001] [0db8] [85a3] [0] [0] [8A2E] [0370] [7334]
可以看到,使用split(":", -1)
保留了最后的空字符串,而使用split(":")
则自动忽略了最后的空字符串。
String转int
比如解中的代码 Integer.parseInt(ipv6[i], 16)
在给定的代码中,Integer.parseInt(ipv6[i], 16)
中的第二个参数 16
表示要解析的整数字符串 ipv6[i]
是一个十六进制表示的整数。
Integer.parseInt(String s, int radix)
是 Java 中用于将字符串转换为整数的方法。radix
参数指定了输入字符串 s
的进制。
当 radix
的值为 16
时,parseInt
方法会将输入的字符串 s
视为一个十六进制数,并将其转换为对应的整数值。
例如:
String hexString = "1A"; // 十六进制表示的字符串 int val = Integer.parseInt(hexString, 16); // 解析十六进制字符串为整数 System.out.println(val); // 输出: 26
在上述例子中,hexString
是一个十六进制表示的字符串,使用 Integer.parseInt(hexString, 16)
将其解析为整数 26
,因为十六进制 1A
对应的十进制数值是 26
。
总结:parseInt(String s, int radix)
方法中的第二个参数 radix
指定了输入字符串 s
的进制,当 radix
为 16
时,输入字符串被视为十六进制数进行解析。