最通俗易懂的判定IPV4和IPV6的算法!

题目描述 

输入一个字符串,检查输入是否为合法的IPV4或者IPV6地址。

IPV4地址: 由4组数字组成,每组数字由"."分隔,第1组每个数字在1到255之间,其余组每个数字在0到255之间。如"172.16.254.1"是一个合法的地址,但是每组数字是不能包含前导0的,如"172.16.254.01"不是一个合法的IPV4地址。

IPV6地址: IPV6地址是有8组16进制数字组成的,每组有4个16进制数字,每组数字之间用":"分隔开。例如"2001:0db8:85a3:0000:0000:8a2e:0370:7334"是一个合法的IPV6地址。在IPV6地址中,可以忽略数字之间的前导0,同时里面的字符不区分大小写,例如"2001:db8:85a3:0:0:8A2E:0370:7334"也是合法的IPV6地址。需要注意的是,每组数字不能为空,例如"2001:0db8:85a3::8A2E:0370:7334"不是合法的IPV6地址。

输入描述 
输入一个字符串, 表示需要检查的字符串。
输出描述 
输出为一行。
如果是合法的IPV4地址,则输出"IPv4"; 如果是合法的IPV6地址,则输出"IPV6"; 否则输出"Neither".
样例输入 
172.16.254.1
2001:0db8:85a3:0:0:8A2E:0370:7334
256.256.256.25
样例输出 
IPv4
IPv6

Neither

Talk is cheap,show me the code!

#include<iostream>
#include<cstdlib>
#include<string>
using namespace std;
int Char_to_Int(string, int, int);
bool Judge_IPv4(string);
bool Judge_IPv6(string);
int main()
{
	string s;
	getline(cin, s);//注意!使用cin会忽略空格,所以用getline来接收空格!
	if (Judge_IPv4(s))
		cout << "IPv4";//如果是IPv4地址,输出IPv4
	else if (Judge_IPv6(s))
		cout << "IPv6";//如果是IPv6地址,输出IPv6
	else
		cout << "Neither";//都不是,输出Neither
	return 0;
}
bool Judge_IPv4(string s)
{
	int len = s.length();
	if (s[0] == '.' || s[len - 1] == '.')
		return false;//如果第一个或最后一个字符是点,则不合法
	int count_dot = 0;//计数点个数,初始化为0
	for (int i = 0; i < len; i++)
	{
		if ((s[i]<'0' || s[i]>'9') && s[i] != '.')
			return false;//如果字符不是数字,也不是点,则不合法
		if (s[i] == '.')//如果碰到点
		{
			count_dot++;//点数+1
			if (s[i + 1] == '.')
				return false;//如果有连续两个点,说明是空组,不合法
			int end = i - 1;//记录点之前的组的末位置
			int j = end;
			for (; j >= 0; j--)//从点之前的组的末位置往前扫描
				if (s[j] == '.')//如果碰到第二个点,跳出循环
					break;
			//如果没碰到点,说明点之前的组为起始组,j循环结束后为-1
			int start = j + 1;//记录点之后的组或起始组的起始位置
			if ((end-start+1)>=2&&s[start] == '0')			
				return false;//重点!如果当前组位数大于等于2且起始位置上的字符为0,说明是前导0,不合法
			int n = Char_to_Int(s, start, end);//将从起始位置开始到末位置之间的字符转换成数字
			if (start == 0)//因为起始组数的范围是1到255,故需要单独处理
			{
				if (n < 1 || n>255)
					return false;//如果数值在1到255之外,则不合法
			}
			else if (n < 0 || n>255)
				return false;//如果数值在0到255之外,则不合法


		}
	}
	if (count_dot != 3)
		return false;//如果点数不为3,则不合法
	for(int i=len-1;i>=0;i--)//处理最后一组字符的情况,从末尾开始倒上来扫描
		if (s[i] == '.')//如果碰到点
		{
			int start = i + 1;//记录点之后的组的起始位置
			int end = len - 1;//记录点之后的组的末位置即字符串的末位置
			if ((end - start + 1) >= 2 && s[start] == '0')
				return false;//重点!如果当前组位数大于等于2且起始位置上的字符为0,说明是前导0,不合法
			int n = Char_to_Int(s, start, end);//将从起始位置开始到末位置之间的字符转换成数字
			if (n < 0 || n>255)
				return false;//如果数值在0到255之外,则不合法
			break;//注意!处理完后要及时跳出循环!
		}
	return true;
}
int Char_to_Int(string s, int start, int end)
{//将字符转换为数字
	int len = s.length();
//如果单独看此函数,则需要判定形参start和end是否合法
	if (start < 0 || end == len||start>end)
	{
		cout << "Illegal Subscript!";
		exit(0);
	}
	int num = 0;
	for (int i = start; i <= end; i++)
		num = num * 10 + (s[i] - '0');//将当前字符的ASCII码减去0的ASCII码即当前字符对应的数字
	//然后按照10进制从高位到低位累加和
	return num;
}
bool Judge_IPv6(string s)
{
	int len = s.length();
	if (s[0] == ':' || s[len - 1] == ':')
		return false;//如果第一个或最后一个字符是冒号,则不合法
	int count_colon = 0;//计数冒号数,初始化为0
	int count_bit=0;//计数每组位数,初始化为0
	for (int i = 0; i < len; i++)
	{
		if ((s[i]<'a' || s[i] > 'f') && (s[i] < 'A' || s[i] > 'F') && (s[i] < '0' || s[i] > '9')&&s[i]!=':')
				return false;//如果字符不是16进制中的字母,不是数字,也不是冒号,则不合法
		count_bit++;//如果字符合法,则位数+1
		if (s[i] == ':')//如果碰到冒号
		{
			count_bit = 0;//位数清0,重新计数
			count_colon++;//冒号数+1
			if (s[i + 1] == ':')
				return false;//如果有连续两个冒号,说明是空组,不合法
		}
		if (count_bit > 4)//如果每组位数超过4,则不合法
			return false;
	}
	if (count_colon != 7)//如果冒号数不为7,则不合法
		return false;
	return true;
}

猜你喜欢

转载自blog.csdn.net/qq_37729102/article/details/80164132