题目链接:
验证IP地址_牛客题霸_牛客网 (nowcoder.com)
题目简介:
描述
编写一个函数来验证输入的字符串是否是有效的 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 是无效的。
说明: 你可以认为给定的字符串里没有空格或者其他特殊字符。
数据范围:字符串长度满足 5≤n≤50
进阶:空间复杂度 O(n),时间复杂度O(n)
题目解法:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
/*
*BM85 验证IP地址
描述
编写一个函数来验证输入的字符串是否是有效的 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 是无效的。
说明: 你可以认为给定的字符串里没有空格或者其他特殊字符。
数据范围:字符串长度满足 5 5≤n≤50
进阶:空间复杂度 O(n) ,时间复杂度 O(n)
*/
/**
* 验证IP地址
* @param IP string字符串 一个IP地址字符串
* @return string字符串
*/
#define PROTOCOL_NEITHER 0 //协议类型
#define PROTOCOL_IPV4 1
#define PROTOCOL_IPV6 2
/// @brief 判断是否有效字符
/// @param c 输入字符
/// @return 0:有效; -1,无效字符
int isVaildChar(char c){
if(c >= 'A' && c <='F')
return 0;
if(c >= 'a' && c <='f')
return 0;
if(c >= '0' && c <='9')
return 0;
return -1;
}
int IsProtocalIPV4(char *IP){
char *tmpIp = IP;
int sectorNum = 0; //用于存储每一段字符的十进制值
int sector = 0; //用于存储输入的IP有多少段
do{ //do while才能判断到结束符
if(*tmpIp == '.' || *tmpIp == '\0'){ //完成一小段的字符获取后,进入判断,是否到末尾以及该段字符是否合法。
if(sectorNum > 255) return -1; //如果该段字符十进制大于255,非法
sectorNum = 0; //该段字符合法 , 清空sectorNum,为下段字符做准备
sector++; //IP段+1
if(*tmpIp == '\0') break; //如果已经到达末尾,则跳出循环。
tmpIp++; //跳过.
}
if(*tmpIp >= '0' && *tmpIp <= '9'){ //判断字符是否为数字
if(sectorNum == 0 && *tmpIp == '0' && *(tmpIp+1) != '.')return -1; //ipv4中每一段开头不能为0,否则非法
sectorNum *= 10; //正常字符以十进制存放在sectorNum
sectorNum += (*tmpIp - '0');
}else{ //异常字符则退出函数
return -1;
}
}while(*tmpIp++ != '\0');
if(sector != 4) //判断是否有4段,多或少都为非法
return -1;
return 0;
}
int IsProtocalIPV6(char *IP){
char *tmpIp = IP;
int sectorCount = 0; //小段的字符数量,注意这里和v4不一样
int sector = 0; //用于存储输入的IP有多少段
do{
if(*tmpIp == ':' || *tmpIp == '\0'){
if(sectorCount == 0 || sectorCount > 4) return -1; //小段的字符数量为0或者大于4都是非法
sectorCount = 0; //清空小段字符数量,为下一次做准备
sector++; //段+1
if(*tmpIp == '\0') break; //如果已经到达末尾,则跳出循环
tmpIp++; //跳过:
}
if(isVaildChar(*tmpIp) == 0){ //判断字符是否为合法:0-9 a-f A-F
sectorCount++;
}else{ //异常字符则退出函数
return -1;
}
}while(*tmpIp++ != '\0');
if(sector != 8) //判断是否有8段,多或少都为非法
return -1;
return 0;
}
char* solve(char* IP ) {
// write code here
char *tmpIp = IP;
char *ret = (char*)malloc(sizeof(char)*10); //给返回值申请空间
ret = "Neither";
int flag_process = PROTOCOL_NEITHER; //设置协议的默认值
while(*tmpIp != '\0'){ //根据. :来区分是使用v4 v6的协议
if(*tmpIp == '.'){
flag_process = PROTOCOL_IPV4;
break;
}
if(*tmpIp == ':'){
flag_process = PROTOCOL_IPV6;
break;
}
tmpIp++;
}
if(flag_process == PROTOCOL_IPV4){ //Ipv4解析
if(IsProtocalIPV4(IP) == 0){ //如果校验完成则设置返回值ret为IPv4
ret = "IPv4";
}
}else if(flag_process == PROTOCOL_IPV6){ //Ipv6解析
if(IsProtocalIPV6(IP) == 0){
ret = "IPv6";
}
}
return ret;
}
/**************************end******************************************/
int main ()
{
char *ip1 = "172.16.254.1";
char *ip2 = "2001:0db8:85a3:0:0:8A2E:0370:7334";
char* ret = solve(ip2);
printf("\r\nret: %s", ret);
return 0;
}