# 【LeetCode】 468. Validate IP Address
## Description
> Write a function to check whether an input string is a valid IPv4 address or IPv6 address or neither.
> IPv4 addresses are canonically represented in dot-decimal notation, which consists of four decimal numbers, each ranging from 0 to 255, separated by dots ("."), e.g.,`172.16.254.1`;
> Besides, leading zeros in the IPv4 is invalid. For example, the address `172.16.254.01` is invalid.
> IPv6 addresses are represented as eight groups of four hexadecimal digits, each group representing 16 bits. The groups are separated by colons (":"). For example, the address `2001:0db8:85a3:0000:0000:8a2e:0370:7334` is a valid one. Also, we could omit some leading zeros among four hexadecimal digits and some low-case characters in the address to upper-case ones, so `2001:db8:85a3:0:0:8A2E:0370:7334` is also a valid IPv6 address(Omit leading zeros and using upper cases).
> However, we don't replace a consecutive group of zero value with a single empty group using two consecutive colons (::) to pursue simplicity. For example, `2001:0db8:85a3::8A2E:0370:7334` is an invalid IPv6 address.
> Besides, extra leading zeros in the IPv6 is also invalid. For example, the address `02001:0db8:85a3:0000:0000:8a2e:0370:7334` is invalid.
> Note: You may assume there is no extra space or special characters in the input string.
> 寫一個程式去判斷輸入字串是否為合法的IPv4位址、IPv6位址還是兩者皆否。
> IPv4位址的規範是dot-decimal,其中包含四個0到255的十進位數字並使用小數點來分開。例如:`172.16.254.1`。
> 另外,前導零在IPv4中是不合法的。例如`172.16.254.01`這個位址是不合法的。
> IPv6用八組四個16進位的字(每組代表16 bits)表示。每組之間使用冒號(":")分開。例如,`2001:0db8:85a3:0000:0000:8a2e:0370:7334`是合法的位址。我們可以省略四個16進制的數字中的前導零,也可以將小寫字母改為大寫,因此`2001:db8:85a3:0:0:8A2E:0370:7334`也是一個合法IPv6的位址(省略前導零和使用大寫字母)。
> 然而,為求簡單,我們不允許使用兩個冒號取代連續值為零的組別,例如`2001:0db8:85a3::8A2E:0370:7334`是不合法的IPv6位址。
> 此外,在IPv6中多餘的前導零是不合法的。例如:`02001:0db8:85a3:0000:0000:8a2e:0370:7334`是不合法的位址。
> 提示: 你可以假設輸入字串中沒有多餘的空白或是特別字元。
## Example:
```
Example 1:
Input: "172.16.254.1"
Output: "IPv4"
Explanation: This is a valid IPv4 address, return "IPv4".
Example 2:
Input: "2001:0db8:85a3:0:0:8A2E:0370:7334"
Output: "IPv6"
Explanation: This is a valid IPv6 address, return "IPv6".
Example 3:
Input: "256.256.256.256"
Output: "Neither"
Explanation: This is neither a IPv4 address nor a IPv6 address.
```
## Solution
* 這一題雖說難度只有Medium,但麻煩程度絕對是Hard。
* 因為需要處理大量的錯誤輸入,會需要蠻多不同的funciton,
* 有時候想不到有哪些錯誤輸入要處理的時候,可以先submit看看,再針對測資去修改。
* 我們先想想演算法流程:
1. 辨識IPv4還是IPv6(使用`.` `:`辨識)
2. 將數字組取出
3. 如果是IPv4:
1. 確認組數
2. 確認空組
3. 檢查前導零
4. 檢查是否為十進位字母(isdigit)
5. 檢查數字大小合法(0~255)
4. 如果是IPv6:
1. 確認組數
2. 確認空組
3. 檢查多餘的前導零(直接檢查組裡面的字數就好)
4. 檢查是否為十六進位字母(isxdigit)
5. 檢查數字大小合法(0~65535)
* 如果submit後發現有錯誤再另外針對錯誤去稍微修改。
* 接下來對於流程中的步驟分別實作即可。
* 如果全部手刻可能有點累,不妨查看看有沒有內建的function或lib可以幫助我們完成功能。
* isdigit、isxdigit協助檢查數字
* stringstream協助hex轉換
* substr協助我們分割字串
---
* 下方code比較難的部分是myIsdigit()裡面使用了function pointer,如果不懂可以自行查詢相關資料或是直接分成兩個function完成。
### Code
```C++=1
class Solution {
public:
bool leaderZero(string num)
{
for(int i = 0; i < num.length(); i++)
{
if(num[i] == '0' && i != num.length() - 1)
return true;
}
return false;
}
bool myIsdigit(string num, int (*op)(int))
{
for(int i = 0; i < num.length(); i++)
{
if(op(num[i]) == 0)
return true;
}
return false;
}
string validIPAddress(string IP) {
char delimiter;
vector<string> nums;
if(IP.length() > 40)
return "Neither";
/* check IP type */
if(find(IP.begin(), IP.end(), '.') != IP.end())
delimiter = '.';
else
delimiter = ':';
/* split numbers */
size_t pos = 0;
string token;
while ((pos = IP.find(delimiter)) != string::npos) {
token = IP.substr(0, pos);
nums.push_back(token);
IP.erase(0, pos + 1);
}
nums.push_back(IP);
/* IPV4 */
if(delimiter == '.')
{
if(nums.size() != 4)
return "Neither";
for(int i = 0; i < nums.size(); i++)
{
if(nums[i].empty()) return "Neither";
if(leaderZero(nums[i])) return "Neither";
if(myIsdigit(nums[i], &isdigit)) return "Neither";
int temp = stoi(nums[i]);
if(temp > 255 || temp < 0) return "Neither";
}
return "IPv4";
}
/* IPV6 */
else
{
if(nums.size() != 8)
return "Neither";
stringstream ss;
int temp;
for(int i = 0; i < nums.size(); i++)
{
if(nums[i].empty()) return "Neither";
if(nums[i].length() > 4) return "Neither";
if(myIsdigit(nums[i], &isxdigit)) return "Neither";
ss << std::hex << nums[i];
ss >> temp;
ss.clear();
if(temp > 65535 || temp < 0) return "Neither";
}
return "IPv6";
}
}
};
```
###### tags: `LeetCode` `C++`