1. 程式人生 > >最通俗易懂的判定IPV4和IPV6的演算法!

最通俗易懂的判定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;
}