原题链接: 468. 验证IP地址
题目大意
给定一个字符串 queryIP
。如果是有效的IPv4
地址,返回 "IPv4"
;如果是有效的IPv6
地址,返回 "IPv6"
;如果不是上述类型的IP
地址,返回 "Neither"
。
有效的IPv4地址 是“x1.x2.x3.x4”
形式的IP地址。 其中 0 <= xi <= 255
且 xi
不能包含 前导零。例如: “192.168.1.1”
、 “192.168.1.0”
为有效IPv4地址, “192.168.01.1”
为无效IPv4地址; “192.168.1.00”
、 “192.168@1.1”
为无效IPv4地址。
一个有效的IPv6地址 是一个格式为“x1:x2:x3:x4:x5:x6:x7:x8”
的IP地址,其中:
1 <= xi.length <= 4
xi
是一个 十六进制字符串 ,可以包含数字、小写英文字母('a'
到'f'
)和大写英文字母('A'
到'F'
)。- 在
xi
中允许前导零。
例如 "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
和 "2001:db8:85a3:0:0:8A2E:0370:7334"
是有效的 IPv6 地址,而 "2001:0db8:85a3::8A2E:037j:7334"
和 "02001:0db8:85a3:0000:0000:8a2e:0370:7334"
是无效的 IPv6 地址。
示例:
输入:queryIP = "172.16.254.1"
输出:"IPv4"
解释:有效的 IPv4 地址,返回 "IPv4"
输入:queryIP = "2001:0db8:85a3:0:0:8A2E:0370:7334"
输出:"IPv6"
解释:有效的 IPv6 地址,返回 "IPv6"
输入:queryIP = "256.256.256.256"
输出:"Neither"
解释:既不是 IPv4 地址,又不是 IPv6 地址
queryIP 仅由英文字母,数字,字符 '.' 和 ':' 组成。
思路
比较复杂的模拟,按要求不断完善。
首先若字符串同时含有’.‘与’:‘则无效,含有单个时分别判断是否为IPv4/IPv6,否则无效。
在判断IPv4/IPv6时,首先实现split函数,将字符串以’.‘或’:'进行分割,采用了双指针算法。
- 对IP分段后,判断段数是否满足,IPv4为4段,IPv6为8段。
- 对于IPv4,分割后的每段字符串应满足:
1.长度为1~3
2.不含前导0
3.每一字符都为数字,再去判断范围是否在0~255内
对于IPv6,分割后的每段字符串应满足:
1.长度为1~4
2.每一字符都为字母(小写英文字母('a'
到'f'
)和大写英文字母('A'
到'F'
))或数字。
其中,在split函数应用时,应在原字符串上加上’.‘或’:‘(split(ip + ':', ':')
),原因在于某些测试案例如图所示:
最后执行的输入: "2001:0db8:85a3:0:0:8A2E:0370:7334:"
此时字符串最后一个字符为’:‘,但无论最后一个字符’:‘是否存在,split输出的效果一致,等价于去除’:'而认为其是IPv6。
因此,split(ip + ':', ':')
会使该情况得到的size()为9(多出一个空字符串),从而正确判断分割后的段数,输出"Neither"。
代码
class Solution {
public:
vector<string> split(string ip, char c){
vector<string> res;
for(int i = 0; i < ip.size(); i ++ ){
int j = i;
string s;
while(ip[j] != c && j < ip.size()) s += ip[j ++ ];
res.push_back(s);
i = j;
}
return res;
}
bool check(char c){
if(c >= '0' && c <= '9') return true;
if(c >= 'A' && c <= 'F') return true;
if(c >= 'a' && c <= 'f') return true;
return false;
}
string check_ipv4(string ip){
auto items = split(ip + '.', '.');
if(items.size() != 4) return "Neither"; // 段数
for(auto item : items){
if(item.empty() || item.size() > 3) return "Neither"; // 长度
if(item.size() > 1 && item[0] == '0') return "Neither"; // 前导0
// 每一字符都为数字
for(char c : item){
if(c < '0' || c > '9') return "Neither";
}
// 取值范围
int t = stoi(item);
if(t > 255) return "Neither";
}
return "IPv4";
}
string check_ipv6(string ip){
auto items = split(ip + ':', ':');
if(items.size() != 8) return "Neither"; // 段数
for(auto item : items){
if(item.empty() || item.size() > 4) return "Neither"; // 每段长度为1~4
// 每个字符应为字符或数字
for(char c : item){
if(!check(c)) return "Neither";
}
}
return "IPv6";
}
string validIPAddress(string ip) {
if(ip.find('.') != -1 && ip.find(':') != -1) return "Neither";
cout << split(ip, ':').size();
if(ip.find('.') != -1) return check_ipv4(ip);
if(ip.find(':') != -1) return check_ipv6(ip);
return "Neither";
}
};