1. 程式人生 > >編寫C++函式:識別一段string字串是IPv4還是IPv6

編寫C++函式:識別一段string字串是IPv4還是IPv6

今天做到Calix(南京凱易迅)的筆試題,其中有一題大致意思是:vector<string>中存有string字串,識別每一個字串是否是ip地址,三種可能:IPv4、IPv6、Neither,將每個字串的識別結果依次存入一個vector<string>中返回。
編寫函式:vector<string> checkIP(vector<string> &ip_array{ }
如:
輸入:
This is not an ip_address!
192.168.1.1
0000: 0123: ff00: 00: ff: 0: 00ff: 1111
輸出:
3
Neither
IPv4
IPv6

輸入:
192.168.1.1
輸出:
1
IPv4

思路如下
1)首先區分IPv4和IPv6,IPv4是通過4段32bits表示出來,每一段對應8bits,十進位制範圍為0~255,每一段用點”.”隔開;
IPv6是通過8段128bits表示出來的,每一段對應16bits,十六進位制範圍為0000~ffff,每一段用冒號”:”隔開。
2)根據段數可以確認可能是IPv4還是IPv6,但只是可能,因為每一段的表示都要進行合法性檢測:如256.168.1.1就是不合法的表示,而gg00顯然也不能表示十六進位制數。那問題來了,如何進行ip_address的每一段檢查呢,很遺憾C++標準庫裡面沒有字元分割函式split(),只有我們可以自己創造了:程式碼如下

#include<iostream>
#include<vector>
#include<string>
using namespace std;

//***函式名:str_split
//***str:待分隔的字串
//***sign:分隔符,如"."、":"等
//***results:將每一段存入results中,特別的當不存在sign時,str整體存入results中

void str_split(const string &str, const string &sign, vector<string> &results)
{
    string
::size_type pos; size_t size = str.size(); for (size_t i = 0; i < size; ++i) { pos = str.find(sign, i); //從第i個位置查詢sign分割符第一次出現的位置,沒有找到則返回npos; if (pos == str.npos) {//將剩餘部分存入 string s = str.substr(i, size); results.push_back(s); break; } if (pos < size) { string s = str.substr(i, pos - i);//把從i開始,長度為pos-i的元素拷貝給s; results.push_back(s); i = pos; } } }

3)理清了前兩點,第三點關於什麼情況下結果是Neither也就清楚了:
a.不存在”.”和”:”,即只有一段,段數不合法;
b.存在間隔符,但是段數不夠(4或8段),段數不合法;
c.存在間隔符,且段數合法,但是每一段表示不合法
程式碼如下:

vector<string> checkIP(vector<string> ip_array)
{
    size_t n = ip_array.size();
    vector<string> results_vec;  //儲存結果

    //vector為空
    if (n == 0)
    {
        results_vec.push_back("Empty");
        return results_vec;
    }

    //存入元素個數
    results_vec.push_back(to_string(n));

    vector<string>::iterator it = ip_array.begin();
    for (; it != ip_array.end(); ++it)
    {
        vector<string> results_4, results_6;
        str_split(*it, ".", results_4);  //results_4儲存ipv4的每段
        str_split(*it, ":", results_6);  //results_6儲存ipv6的每段

        //地址段數不合法
        if(results_4.size() != 4 && results_6.size() != 8)
        {
            results_vec.push_back("Neither");
            continue;
        }

        //段數合法(4段),可能是IPv4,接下來判斷每一段的合法性
        if (results_4.size() == 4)  
        {
            vector<string>::iterator it_4 = results_4.begin();

            for (; it_4 != results_4.end(); ++it_4)
            {
                int a = atoi((*it_4).c_str());
                if (a < 0 || a > 255)
                    break;
            }
            if (it_4 == results_4.end())
                results_vec.push_back("IPv4");
            else
                results_vec.push_back("Neither");
        }

        //段數合法(8段),可能是IPv6,接下來判斷每一段的合法性
        if (results_6.size() == 8)
        {
            vector<string>::iterator it_6 = results_6.begin();

            for (; it_6 != results_6.end(); ++it_6)
            {
                size_t it6_size = (*it_6).size();
                if (it6_size <= 0 || it6_size > 4)  //IPv6的每段的十六進位制數的位數不合法
                    break;

                size_t j = 0;
                while(j < it6_size)
                {//十六進位制表示的合法性檢測
                    char s = (*it_6)[j];
                    if ((s >= '0' && s <= '9') ||
                        (s >= 'a' && s <= 'f') ||
                        (s >= 'A' && s <= 'F'))
                        ++j;
                    else
                        break;
                }
                if (j != it6_size)  //存在某一位的十六進位制表示不合法
                    break;
            }
            if (it_6 == results_6.end())  //所有位的十六進位制表示均合法
                results_vec.push_back("IPv6");
            else
                results_vec.push_back("Neither");
        }
    }

    return results_vec;  
}

接下來main函式測試一下程式碼:

int main()
{
    vector<string> ip_array = { "This is not an ip_address!", "192.168.1.1", "256.168.1.1", "0000:0123:ff00:00:ff:1234:00ff:1111" ,"0000:0123:ff00:00:ff:1234:00ff" };
    vector<string> results;
    results = checkIP(ip_array);
    for (vector<string>::iterator it = results.begin(); it != results.end(); ++it)
        cout << *it << endl;

    return 0;
}

結果

//***output:
5
Neither
IPv4
Neither
IPv6
Neither
請按任意鍵繼續. . .