[编程题]识别有效的IP地址和掩码并进行分类统计

Talk is cheap, show me the code.

一、问题描述

请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。

所有的IP地址划分为 A,B,C,D,E五类

A类地址1.0.0.0~126.255.255.255;

B类地址128.0.0.0~191.255.255.255;

C类地址192.0.0.0~223.255.255.255;

D类地址224.0.0.0~239.255.255.255;

E类地址240.0.0.0~255.255.255.255

私网IP范围是:

10.0.0.0~10.255.255.255

172.16.0.0~172.31.255.255

192.168.0.0~192.168.255.255

子网掩码为前面是连续的1,然后全是0。(例如:255.255.255.32就是一个非法的掩码)
本题暂时默认以0开头的IP地址是合法的,比如0.1.1.2,是合法地址

输入描述:

多行字符串。每行一个IP地址和掩码,用~隔开。

输出描述:

统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数,之间以空格隔开。

输入例子:

10.70.44.68~255.254.255.0
1.0.0.1~255.0.0.0
192.168.0.2~255.255.255.0
19..0.~255.255.255.0

输出例子:

1 0 1 0 0 2 1

二、问题分析

题目有些地方没有讲清楚,害我花了很多时间去揣摩意思。首先要确定ip以0开头和以127开头都是正确的输入,不过不属于任何一类而已,然后判断掩码正确与否时除了必须1都在0前面,还要注意255.255.255.255是错误的掩码。另外还要注意私网ip其实也是ABCDE类中某一类,两类都要加一。

解题方式1:

全部代码按逻辑来,不投机取巧。

#include <iostream>
#include <string>
#include <sstream>
#include <bitset>
using namespace std;

int main()
{
    int aNum = 0, bNum = 0, cNum = 0, dNum = 0, eNum = 0, errNum = 0, priNum = 0;
    int ip[4] = {0}, code[4] = {0};
    string line;
    while (cin >> line)
    {
        string ipstr, codestr;
        bool ipflag = false, codeflag = false;
        istringstream is(line);
        getline(is, ipstr, '~');
        string s;
        int i = 0;
        istringstream is1(ipstr);
        while (getline(is1, s, '.'))
        {
            if (s == "")
            {
                break;
            } else {
                int temp = atoi(s.c_str());
                if (temp < 0 || temp > 255)
                {
                    break;
                } else {
                    if (i < 4)
                        ip[i] = temp;
                    i++;
                }
            }
        }
        if (i != 4)
        {
            errNum += 1;
            continue;
        } else {
            ipflag = true;
        }
        getline(is, codestr, '~');
        istringstream is2(codestr);
        string s1;
        int j = 0;
        while (getline(is2, s1, '.'))
        {
            int temp = atoi(s1.c_str());
            if (s1 == "")
                break;
            else {
                if (temp < 0 || temp > 255)
                {
                    break;
                } else {
                    bitset<8> bs(temp);
                    int t = -1;
                    for (int i = bs.size() - 1; i >= 0; i--)
                    {
                        if (bs[i] == 0)
                        {
                            t = i;
                            break;
                        }
                    }
                    for (int i = t - 1; i >= 0; i--)
                    {
                        if (bs[i] != 0)
                        {
                            temp = -1;
                            break;
                        }
                    }
                    if (temp == -1)
                        break;
                    else {
                        code[j] = temp;
                        j++;
                    }
                }
            }
        }
        if (j != 4)
        {
            errNum++;
            continue;
        } else {
            j = 0;
            while (j < 4 && code[j] == 255)
            {
                j++;
            }
            for (int i = j + 1; i < 4; i++)
            {
                if (code[i] != 0)
                {
                    j = -1;
                    break;
                }
            }

            if (j == -1 || code[3] == 255)
            {
                errNum++;
                continue;
            } else {
                codeflag = true;
            }
        }
        if (ipflag && codeflag)
        {
            if (ip[0] >= 1 && ip[0] <= 126)
            {
                aNum++;
                if (ip[0] == 10)
                    priNum++;
            } else if (ip[0] >= 128 && ip[0] <= 191) {
                bNum++;
                if (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31)
                    priNum++;
            } else if (ip[0] >= 192 && ip[0] <= 223) {
                cNum++;
                if (ip[0] == 192 && ip[1] == 168)
                    priNum++;
            } else if (ip[0] >= 224 && ip[0] <= 239) {
                dNum++;
            } else if (ip[0] >= 240 && ip[0] <= 255) {
                eNum++;
            }
        }
    }
    cout << aNum << " " << bNum << " " << cNum << " " << dNum << " " << eNum << " " << errNum << " " << priNum << endl;
    return 0;
}

虽然全部逻辑实现,但是逻辑不算直观,思路是先判断输入的ip是否有效,有效则存储在ip数组中,然后判断掩码每个数字是不是符合规范的,每个数字都符合规范就把掩码都存储在code数组中,再判断整个32位掩码是不是符合规范的,这里特别要注意出去255.255.255.255的情况,如果ip和掩码都符合规范,再进行分类,同时属于私网和公网某类的两类都需要计数加一。

解题方式2:

下面这种方式判断掩码是否正确是通过列举出8位的所有可能值一次判断的,虽然很直观,但不是很满意。

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

int stringtoint(string str){
    stringstream ss;
    ss<<str;
    int x;
    ss>>x;
    return x;
}

vector<int> toint(string str){
    vector<int> res;
    string temp;
    int ele;
    for(int i=0;i<str.length();i++){
        if(str[i]!='.'){
            temp.push_back(str[i]);
        }
        else{
            ele=stringtoint(temp);
            temp.clear();
            res.push_back(ele);
        }
    }
    ele=stringtoint(temp);
    res.push_back(ele);
    return res;
}

bool maskisvalid(vector<int> res){
    if(res.size()!=4)
        return false;
    if(res[0]==255){
        if(res[1]==255){
            if(res[2]==255){
                if(res[3]==254||res[3]==252||res[3]==248||res[3]==240||res[3]==224||res[3]==192||res[3]==128||res[3]==0){
                    return true;
                }
                else{
                    return false;
                }
            }
            else{
                if(res[2]==254||res[2]==252||res[2]==248||res[2]==240||res[2]==224||res[2]==192||res[2]==128||res[2]==0){
                    if(res[3]==0){
                        return true;
                    }
                    else{
                        return false;
                    }
                }
            }
        }
        else{
            if(res[1]==254||res[1]==252||res[1]==248||res[1]==240||res[1]==224||res[1]==192||res[1]==128||res[1]==0){
                if(res[3]==0&&res[2]==0){
                    return true;
                }
                else{
                     return false;
                    }
             }
        }           
    }
    else{
            if(res[0]==254||res[0]==252||res[0]==248||res[0]==240||res[0]==224||res[0]==192||res[0]==128){
                if(res[3]==0&&res[2]==0&&res[1]==0){
                    return true;
                }
            }
                else{
                     return false;
            }      
    }
    return false;
}

int main(){
    string str;
    int* res=new int[7];
    for(int j=0;j<7;j++)
        res[j]=0;
    while(cin>>str){
         string ipstring;
         string maskstring;
        vector<int> ip,mask;
        int i=0;
        for(;str[i]!='~';i++){
            ipstring.push_back(str[i]);
        }
        i++;
        for(;i<str.length();i++){
            maskstring.push_back(str[i]);
        }
        ip=toint(ipstring);
        mask=toint(maskstring);
        if(maskisvalid(mask)){
            if(ip[1]>=0&&ip[1]<=255&&ip[2]>=0&&ip[2]<=255&&ip[3]>=0&&ip[3]<=255){
                if(ip[0]>=1&&ip[0]<=126){
                    res[0]++;
                    if(ip[0]==10)
                        res[6]++;
                }
                else if(ip[0]>=128&&ip[0]<=191){
                    res[1]++;
                    if(ip[0] == 172 && ip[1] >= 16 && ip[1] <= 32)
                        res[6]++;
                }
                else if(ip[0]>=192&&ip[0]<=223){
                    res[2]++;
                    if(ip[0] == 192 && ip[1] == 168)
                        res[6]++;
                }
                else if(ip[0]>=224&&ip[0]<=239){
                    res[3]++;
                }
                else if(ip[0]>=240&&ip[0]<=255){
                    res[4]++;
                }  
            } 
        }
        else{
                res[5]++;
        }
    }
    cout<<res[0]<<" "<<res[1]<<" "<<res[2]<<" "<<res[3]<<" "<<res[4]<<" "<<res[5]<<" "<<res[6]<<endl;
    delete [] res;
    return 0;
}

解题方式3:

这种方式分层比较清晰,虽然也是通过列举法来判断掩码,但是代码可读性最强。

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

void split(string& str, vector<string>& strs){
    int pos=str.find('.');
    while(pos>=0){
        strs.push_back(str.substr(0, pos));
        str=str.substr(pos+1, str.length()-pos-1);
        pos=str.find('.');
    }
    strs.push_back(str);
}

bool checkNum(string& str){
    if(str.size()==0 || str.size()>3)
        return false;
    for(int i=0; i<str.size(); i++){
        if(str[i]<'0' || str[i]>'9')
            return false;
    }
    int num=atoi(str.c_str());
    if(num>=0 && num<=255)
        return true;
    return false;
}

bool checkIP(vector<string>& segs){
    if(segs.size()!=4)
        return false;
    for(int i=segs.size()-1; i>=0; i--){
        if(!checkNum(segs[i]))
            return false;
    }
    //if(atoi(segs[0])==127)
    //    return false;
    return true;
}

bool checkMask(vector<string>& segs){
    if(segs.size()!=4)
        return false;
    bool start=false;
    for(int i=0; i<segs.size(); i++){
        if(!checkNum(segs[i]))
            return false;
        int num=atoi(segs[i].c_str());
        if(start){
            if(num!=0)
                return false;
        }else{
            if(num!=255){
                if(num==0 || num==128 || num==192 || num==224 || num==240 || num==248 || num==252 || num==254)
                    start=true;
                else
                    return false;
            }
        }   
    }
    if(atoi(segs[3].c_str())==255)
        return false;
    return true;
}

void classify(vector<string>& ip, vector<int>& counter){
    int n1=atoi(ip[0].c_str());
    int n2=atoi(ip[1].c_str());
    if(n1>=1 && n1<=126){
        if(n1==10)
            counter[6]++;
        counter[0]++;
    }else if(n1>=128 && n1<=191){
        if(n1==172 && n2>=16 && n2<=31)
            counter[6]++;
        counter[1]++;
    }else if(n1>=192 && n1<=223){
        if(n1==192 && n2==168)
            counter[6]++;
        counter[2]++;
    }else if(n1>=224 && n1<=239)
        counter[3]++;
    else if(n1>=240 && n1<=255)
        counter[4]++;
}

int main(){
    vector<int> counter(7, 0);
    int W=0, P=0;
    string str;
    while(cin>>str){
        int pos=str.find('~');
        string ip=str.substr(0, pos);
        string mask=str.substr(pos+1, str.length()-pos-1);
        vector<string> ip_segs, mask_segs;
        split(ip, ip_segs);
        split(mask, mask_segs);
        if(!checkIP(ip_segs) || !checkMask(mask_segs))
            counter[5]++;
        else
            classify(ip_segs, counter);
    }
    cout<<counter[0]<<" "<<counter[1]<<" "<<counter[2]<<" "<<counter[3]<<" "<<counter[4]<<" "<<counter[5]<<" "<<counter[6]<<endl;
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值