最通俗易懂的判定IPV4和IPV6的演算法!
阿新 • • 發佈:2019-01-03
題目描述
輸入一個字串,檢查輸入是否為合法的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; }