首页 > 试题广场 >

识别有效的IP地址和掩码并进行分类统计

[编程题]识别有效的IP地址和掩码并进行分类统计
  • 热度指数:356334 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解

请解析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.0239.255.255.255;

E类地址从240.0.0.0255.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就是一个非法的掩码)
(注意二进制下全是1或者全是0均为非法子网掩码)

注意:
1. 类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略
2. 私有IP地址和A,B,C,D,E类地址是不冲突的



输入描述:

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

请参考帖子https://www.nowcoder.com/discuss/276处理循环输入的问题。


输出描述:

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

示例1

输入

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
127.69.131.137~255.70.255.255

输出

1 0 1 0 0 2 1

说明

10.70.44.68~255.254.255.0的子网掩码非法,19..0.~255.255.255.0的IP地址非法,所以错误IP地址或错误掩码的计数为2;
1.0.0.1~255.0.0.0是无误的A类地址;
192.168.0.2~255.255.255.0是无误的C类地址且是私有IP;
127.69.131.137~255.70.255.255 计数忽略
所以最终的结果为1 0 1 0 0 2 1        
示例2

输入

0.201.56.50~255.255.111.255
127.201.56.50~255.255.111.255

输出

0 0 0 0 0 2 0

说明

类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略         
import sys

def ignore(ip):
    if (ip[0] == '0'&nbs***bsp;ip[0] == '127') and ip[1] and ip[2] and ip[3]:
        return True
    return False    

def isip(ip):
    for i in ip:
        if  not 0<=int(i)<=255: return False
    return True    

def ismask(mask):
    mask = map(int,mask)
    maskstr = ''
    for m in mask:
        if not (m == 0&nbs***bsp;126 < m < 256):
            return False
        bin_m = '0'*8 if m==0 else bin(m)[2:]
        maskstr = maskstr + bin_m
#     print(maskstr)
    i,j = 0,31
    while maskstr[i]=='1' and i < 32: i+=1
    while maskstr[j]=='0' and j > -1: j-=1
    if i==32&nbs***bsp;j == -1&nbs***bsp;i-j!=1:
#         print(i,j)
        return False
    return True

a,b,c,d,e,err,pr = 0,0,0,0,0,0,0

for line in sys.stdin:
    ip, mask = line.strip().split('~')
    ip = ip.split('.')
    mask = mask.split('.')
#     print(ip,mask)
    if ignore(ip): continue
    try:
        if not isip(ip)&nbs***bsp;not ismask(mask):
            err += 1
            continue
    except:
        err += 1
        continue
    ip = list(map(int,ip))
    if 1 <= ip[0] <= 126: a += 1
    elif 128 <= ip[0] <= 191: b += 1
    elif 192 <= ip[0] <= 223: c += 1
    elif 224 <= ip[0] <= 239: d += 1
    elif 240 <= ip[0] <= 255: e += 1
    
    if ip[0]==10&nbs***bsp;(ip[0]==172 and 16<=ip[1]<=31)&nbs***bsp;(ip[0]==192 and ip[1]==168):
        pr += 1
print(a,b,c,d,e,err,pr)

发表于 2022-07-09 17:34:34 回复(0)
#include<bits/stdc++.h>
using namespace std;
int a=0,b=0,c=0,d=0,e=0,error_data=0,private_data=0;
bool valid_mask(string mask){
    bool ret = 1;
    int one_num = 0;
    vector<int> int_data;
    
    int left = 0;
    for(int index = 0 ; index < mask.size() ; index++){//将string类型的地址转换为int型
        string temp;
        
        if(index == mask.size() - 1){
            temp = mask.substr(left,index-left+1);
            int_data.push_back(stoi(temp));
        }
        
        if(mask[index] == '.'){
            temp = mask.substr(left,index-left);
            int_data.push_back(stoi(temp));
        }else{
            continue;
        }
        

        left = index + 1;
    }
    
    //如果按照正常的掩码规则,根据1最后出现位置,推理应该有多少个1
    int j;
    for(j = int_data.size() - 1 ; j >= 0 ; j--){
        int cur = int_data[j];
        
        if(cur&0x1 == 1){
            one_num = 8;
            break;
        }else
        {
            int flag = 0;
            for(int s = 0 ; s < 7 ; s++){
                cur = cur >> 1;
                if(cur&0x1 == 1){
                    one_num = 7-s;
                    flag = 1;
                    break;
                }
            } 
            
            if(flag == 1)
                break;
        }
        
          
    }
    one_num = one_num + j*8;//推理出的1的个数
    if(one_num == 32 || one_num == 0)
        return false;
    
    
    int count = 0;
    for(int index = 0 ; index < int_data.size() ; index++){//计算掩码中实际1出现的次数
        int temp = int_data[index];
        while(temp){
            count += temp&0x1;
            temp = temp >> 1;
        }
    }
    
    ret = count==one_num? true:false;//若干推理的次数和实际计算相等则掩码正确,否则掩码不符合要求
    return ret;
}

int ip_net_type(string ip_net,string mask){
    /*
    返回1 表A类地址
    返回2 表B类地址
    返回3 表C类地址
    返回4 表D类地址
    返回5 表E类地址
    
    返回8 计数忽略
    */
    int ret = 8;
    
    vector<int> int_data;
    
    int left = 0;
    for(int index = 0 ; index < ip_net.size() ; index++){//将string类型的地址转换为int型
        string temp;
        
        if(index == ip_net.size() - 1){
            temp = ip_net.substr(left,index-left+1);
            int_data.push_back(stoi(temp));
        }
        
        if(ip_net[index] == '.'){
            temp = ip_net.substr(left,index-left);
            int_data.push_back(stoi(temp));
        }else{
            continue;
        }
        left = index + 1;
    }
    
    
    //判断ip地址属于哪一类型
    if(int_data[0] >= 1 && int_data[0] <= 126){
        if(int_data[0] == 10){//属于私有ip
            if(valid_mask(mask)){//同时掩码符合规则
                private_data++;
            }
        }
        return 1;
        
    }else if(int_data[0] >= 128 && int_data[0] <= 191){
        if(int_data[0] == 172 && int_data[1] >= 16 && int_data[1] <= 31){
            if(valid_mask(mask)){
                private_data++;
            }
        }
        return 2;
        
    }else if(int_data[0] >= 192 && int_data[0] <= 223){
        if(int_data[0] == 192 && int_data[1] == 168){
            if(valid_mask(mask)){
                private_data++;
            }
        }
        return 3;
    }else if(int_data[0] >= 224 && int_data[0] <= 239){
        return 4;
    }else if(int_data[0] >= 240 && int_data[0] <= 255){
        return 5;
    }
    
    
    return ret;
}

bool get_ip_valid(string ip_net){
    int left = 0;
    for(int index = 0 ; index < ip_net.size() ; index++){
        if(index == ip_net.size() - 1 && ip_net[index] == '.'){
            return false;
        }
        
        if(ip_net[index] == '.'){
            if(left == index){
                return false;
            }else{
                left = index+1;
            }
        }
        
        
    }
    return true;
}



int main()
{
    
    string ipdata;
    
    while(getline(cin , ipdata))
    {
        int index = 0;
        int len = ipdata.size();
        
        while(ipdata[index] != '~')
            index++;
        
        string ip_net = ipdata.substr(0,index);//ip地址
        string mask = ipdata.substr(index+1,len-index-1);//子网掩码
        
        if(get_ip_valid(ip_net)){//ip合法
            int ip_type = ip_net_type(ip_net,mask);//ip属于哪一类型
            if(ip_type != 8){//ip属于规定的类型;当返回值为8时,ip属于定义类型以外
                if(valid_mask(mask)){
                    switch(ip_type){
                        case 1:{
                            a++;
                            break;
                        }case 2:{
                            b++;
                            break;
                        }case 3:{
                            c++;
                            break;
                        }case 4:{
                            d++;
                            break;
                        }case 5:{
                            e++;
                            break;
                        }default:break;
                    }
                    
                }else{
                    error_data++;
                }
            }
        }else{
            error_data++;
        }
    }
    cout<< a <<" "<<b<<" "<<c<<" "<<d<<" "<<e<<" "<<error_data<<" "<<private_data<<endl;
    return 0;
}

发表于 2022-07-07 20:49:03 回复(0)
// C语言版本。
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

int is_legal_ip(char* ipaddr)
{
    char* tmp_ipaddr = strdup(ipaddr);
    int count = 0;
    char* tmp = strtok(tmp_ipaddr, ".");
    if (!tmp)
        return false;
    // int num = atoi(tmp);
    // if (num == 0 || num == 127)  // 这种IP地址需要忽略
    //    return false;

    while (tmp) {
        count++;
        int num = atoi(tmp);
        if (num < 0 || num >  255)
            return false;
        tmp = strtok(NULL, ".");
    }

    if (count != 4)
        return false;
    return true;
}

bool is_legal_mask(char* mask)
{
    char* tmp_mask = strdup(mask);
    unsigned int num = 0;
    char* tmp = strtok(tmp_mask, ".");
    while (tmp) {
        num = num << 8;
        num += atoi(tmp);
        tmp = strtok(NULL, ".");
    }
    if (!num) // 如果32位无符号整数0,则表示输入的全是0,就是非法的掩码
        return false;
    num = ~num + 1; // 对整数取反 + 1,得到的数如果等于1,则表示输入的全是1,也是非法掩码
    if (num == 1)
        return false;
    if ((num & (num - 1)) != 0) // 类似 0001000 & 0000111 是等于0的,非0,则表示掩码有问题。
        return false;
    return true;
}

bool is_private_ip(char* ipaddr)
{
    char* tmp_ipaddr = strdup(ipaddr);
    char* tmp = strtok(tmp_ipaddr, ".");
    int num1 = atoi(tmp);
    if (num1 != 10 && num1 != 172 && num1 != 192)
        return false;

    tmp = strtok(NULL, ".");
    int num2 = atoi(tmp);
    if (num1 == 172 && (num2 < 16 || num2 > 31))
        return false;
    if (num1 == 192 && (num2 != 168))
        return false;
    return true;
}

int main()
{
    char arr[1000][100] = { 0 };
    int cnt = 0;
    while (scanf("%s", arr[cnt]) != EOF)
        cnt++;

    int a = 0;
    int b = 0;
    int c = 0;
    int d = 0;
    int e = 0;
    int err = 0;
    int pri = 0;

    for (int i = 0; i < cnt; i++) {
        char* ipaddr = strtok(arr[i], "~");
        if (!ipaddr) {
            err++;
            continue;
        }
        char* mask = strtok(NULL, "~");
        if (!mask) {
            err++;
            continue;
        }
        if (!is_legal_ip(ipaddr) || !is_legal_mask(mask)) {
            err++;
            continue;
        }
        if (is_private_ip(ipaddr))
            pri++;

        char* tmp = strtok(ipaddr, ".");
        int num = atoi(tmp);
        if (1 <= num && num <= 126)
            a++;
        else if (128 <= num && num <= 191)
            b++;
        else if (192 <= num && num <= 223)
            c++;
        else if (224 <= num && num <= 239)
            d++;
        else if (240 <= num && num <= 255)
            e++;
        // else // 忽略10 和 127 开头的IP地址。
    }
    printf("%d %d %d %d %d %d %d\n", a, b, c, d, e, err, pri);
    return 0;
}

发表于 2021-08-02 00:59:37 回复(0)
#include <iostream>
#include <vector>
#include <string>
#include <bitset>

using namespace std;
int main()
{
    string str;
    int Anum=0,Bnum=0,Cnum=0,Dnum=0,Enum=0,Ernum=0,Snum=0;
    while(getline(cin,str))
    {
        size_t pos=str.find("~");
        if(pos!=string::npos)
        {
            string a=str.substr(0,pos);
            string b=str.substr(pos+1,str.size()-pos-1);
            vector<string> temp1;
            vector<string> temp2;
            
            size_t pos1=a.find(".");
            while(pos1!=string::npos)
            {
                temp1.push_back(a.substr(0,pos1));
                a=a.substr(pos1+1,a.size()-pos1-1);
                pos1=a.find(".");
            }
            if(!a.empty())
            temp1.push_back(a);
          
            size_t pos2=b.find(".");
            while(pos2!=string::npos)
            {
                temp2.push_back(b.substr(0,pos2));
                b=b.substr(pos2+1,b.size()-pos2-1);
                pos2=b.find(".");
            }
            if(!b.empty())
            temp2.push_back(b);
            
            bool IsNext=true;
            
            if(IsNext)
            {
                string strMask;
                for(int i=0;i<temp2.size();i++)
                {
                    bitset<8> b(stoi(temp2[i]));
                    strMask+=b.to_string();
                }
                size_t pos=strMask.find("01");
                size_t pos1=strMask.find("0");
                size_t pos2=strMask.find("1");
                
                if(pos==string::npos&&!(pos1==string::npos&&pos2!=string::npos)
                   &&!(pos2==string::npos&&pos1!=string::npos))
                {
                    IsNext=true;
                }
                else
                {
                    IsNext=false;
                    Ernum++;
                    continue;
                }
            }
            
            vector<int> t1;
            if(IsNext)
            {
                for(int i=0;i<temp1.size();i++)
                {
                    if(temp1[i].empty())
                    {
                        Ernum++;
                        IsNext=false;
                        break;
                    }
                    else
                    {
                        int value=stoi(temp1[i]);
                        if(i==0&&(value==0||value==127))
                        {
                            IsNext=false;
                            break;
                        }
                        else if(value>255||value<0)
                        {
                            Ernum++;
                            IsNext=false;
                            break;
                        }
                        else
                        {
                            t1.push_back(value);
                        }
                    }
                }
            }
            
            if(IsNext)
            {
                if(t1[0]>=1&&t1[0]<=126)
                {
                    Anum++;
                }
                else if(t1[0]>=128&&t1[0]<=191)
                {
                    Bnum++;
                }
                else if(t1[0]>=192&&t1[0]<=223)
                {
                    Cnum++;
                }
                else if(t1[0]>=224&&t1[0]<=239)
                {
                    Dnum++;
                }
                else if(t1[0]>=240&&t1[0]<=255)
                {
                    Enum++;
                }
                
                if(t1[0]==10)
                {
                    Snum++;
                }
                else if(t1[0]==172&&t1[1]>=16&&t1[1]<=32)
                {
                    Snum++;
                }
                else if(t1[0]==192&&t1[1]==168)
                {
                    Snum++;
                }
            }
        }
    }
    cout<<Anum<<" "<<Bnum<<" "<<Cnum<<" "<<Dnum<<" "<<Enum<<" "<<Ernum<<" "<<Snum;
}

发表于 2021-06-29 03:50:04 回复(0)
修修改改半天才做出来,需要注意的是,不在ABCDE里面的IP地址,不算是错误的地址,掩码错才算错,如果掩码对则忽略这部分IP的计数即可。
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<unordered_set>
#include<set>
using namespace std;

int checkip(string ip,bool& priva) {
    int len=ip.size();
    vector<int> a;
    int pre=0,i;
    for(i=0;i<len;++i) {
        if(ip[i]=='*') {
            return 0; //含有*的,计数时忽略
        }
        if(ip[i]=='.') {
            if(i==pre) {
                //连续的点
                return -1; //错误的IP地址
            }
            int x=atoi(ip.substr(pre,i-pre).c_str());
            pre=i+1;
            if(x>255)
                return -1;
            a.push_back(x);
        } else if(ip[i]<'0' || ip[i]>'9') {
            return -1; //非法字符,错误ip
        }
    }
    if(i==pre) {
        //连续的点
        return -1; //错误的IP地址
    }
    int x=atoi(ip.substr(pre,i-pre).c_str());
    pre=i+1;
    if(x>255)
        return -1;
    a.push_back(x);
    if(a.size()!=4)
        return -1; //错误ip
    if(a[0]>=1 && a[0]<=126) {
        if(a[0]==10)
            priva=true; //私有ip
        return 1;
    }
    if(a[0]>=128 && a[0]<=191) {
        if(a[0]==172 && a[1]>=16 && a[1]<=31)
            priva=true;
        return 2;
    }
    if(a[0]>=192 && a[0]<=223) {
        if(a[0]==192 && a[1]==168)
            priva=true;
        return 3;
    }
    if(a[0]>=224 && a[0]<=239)
        return 4;
    if(a[0]>=240 && a[0]<=255)
        return 5;
    return 0;
}
int checkmask(string mask) {
    //判断子网掩码
    int len=mask.size();
    vector<int> a;
    int pre=0,i;
    for(i=0;i<len;++i) {
        if(mask[i]=='.') {
            if(i==pre) {
                return -1; //错误
            }
            int x=atoi(mask.substr(pre,i-pre).c_str());
            pre=i+1;
            if(x>255)
                return -1;
            a.push_back(x);
        } else if(mask[i]<'0' || mask[i]>'9') {
            return -1; //非法字符
        }
    }
    if(i==pre) {
        return -1; //错误
    }
    int x=atoi(mask.substr(pre,i-pre).c_str());
    pre=i+1;
    if(x>255)
        return -1;
    a.push_back(x);
    if(a.size()!=4)
        return -1; //错误
    int tem=a[0]+a[1]+a[2]+a[3];
    if(tem==0 || tem==255*4)
        return -1; //全0或者全1均为非法
    bool zero=false;
    unordered_set<int> s={128,192,224,240,248,252,254,255};
    for(int i=0;i<4;++i) {
        if(a[i]==0) {
            zero=true;
            continue;
        }
        if(a[i]!=0 && zero==true)
            return -1;
        if(s.count(a[i])==0)
            return -1;
        if(a[i]!=255)
            zero=true;
    }
    return 1;
}
int main()
{
    string str;
    int a=0,b=0,c=0,d=0,e=0;
    int err=0;
    int priv=0;
    while(cin>>str) {
        int i=0;
        for(;i<str.size();++i) {
            if(str[i]=='~')
                break;
        }
        string ip=str.substr(0,i);
        string mask=str.substr(i+1);
        bool isPrivate=false;
        int x=checkip(ip,isPrivate);
        if(x==-1) {
            err++;
            continue;
        }
        int y=checkmask(mask);
        if(y==-1) {
            err++; //错误IP或者掩码
            continue;
        }
        switch(x){
            case 1: a++; break;
            case 2: b++; break;
            case 3: c++; break;
            case 4: d++; break;
            case 5: e++; //cout<<str<<endl; break;
        }
        if(isPrivate) {
            //是合法IP,且判断是否私有IP
            priv++;
        }
    }
    printf("%d %d %d %d %d %d %d\n",a,b,c,d,e,err,priv);
    return 0;
}


编辑于 2021-06-24 12:26:52 回复(0)
按照题目的逻辑进行分类就行:
(1) 判断掩码的合法性,如果掩码不合法,直接错误数+1,判断下一行。
(2) 判断是不是【0.*.*.*】和【127.*.*.*】型,如果是就直接跳过。
(3) 依照题意对IP地址进行分类,但是对于ABC类,还需要判断一下是不是私有ip,如果是私有ip,则相应类别ip和私有ip的计数都要+1。
对于某个数,判断其二进制表示是否满足前面全是1后面全是0,只需要检查一下二进制串中是否有"01"这个子串就行了。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.HashMap;

public class Main {
    static HashMap<String, Integer> counter = new HashMap<>();
    public static void main(String[] args) throws IOException {
        counter.put("A", 0);
        counter.put("B", 0);
        counter.put("C", 0);
        counter.put("D", 0);
        counter.put("E", 0);
        counter.put("Error", 0);
        counter.put("private", 0);
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line;
        while((line = br.readLine()) != null){
            String[] params = line.trim().split("~");
            classifier(params[0].split("\\."), params[1].split("\\."));
        }
        System.out.println(counter.get("A") + " " + counter.get("B") + " " + counter.get("C") + " " + 
                           counter.get("D") + " " + counter.get("E") + " " + counter.get("Error") + " " + 
                           counter.get("private"));
    }
    
    private static void classifier(String[] ip, String[] mask) {
        if(!isRightMask(mask)){
            // 掩码不对,直接错误数加1,不再判断ip的类别
            counter.put("Error", counter.getOrDefault("Error", 0) + 1);
            return;
        }
        if(ip[0].length() == 0){
            counter.put("Error", counter.get("Error") + 1);
            return;
        }
        int num = Integer.parseInt(ip[0]);
        // 忽略【0.*.*.*】和【127.*.*.*】
        if(num == 0 || num == 127) return;
        // ip地址分类
        if(num >= 1 && num <= 126){
            // 检查是不是A类ip
            boolean isA = true;
            for(int i = 1; i < 4; i++){
                if(ip[i].length() == 0) {
                    isA = false;
                    break;
                }
                int temp = Integer.parseInt(ip[i]);
                if(temp < 0 || temp > 255){
                    isA = false;
                    break;
                }
            }
            if(isA){
                counter.put("A", counter.get("A") + 1);
                // 检查一下是不是私有ip
                if(num == 10)  counter.put("private", counter.get("private") + 1);
            }else
                counter.put("Error", counter.get("Error") + 1);
        }else if(num >= 128 && num <= 191){
            // 检查是不是B类ip
            boolean isB = true;
            for(int i = 1; i < 4; i++){
                if(ip[i].length() == 0) {
                    isB = false;
                    break;
                }
                int temp = Integer.parseInt(ip[i]);
                if(temp < 0 || temp > 255){
                    isB = false;
                    break;
                }
            }
            if(isB){
                counter.put("B", counter.get("B") + 1);
                // 检查一下是不是私有ip
                if(num == 172 && Integer.parseInt(ip[1]) >= 16 && Integer.parseInt(ip[1]) <= 31)
                    counter.put("private", counter.get("private") + 1);
            }else
                counter.put("Error", counter.get("Error") + 1);
        }else if(num >= 192 && num <= 223){
            // 检查是不是C类ip
            boolean isC = true;
            for(int i = 1; i < 4; i++){
                if(ip[i].length() == 0) {
                    isC = false;
                    break;
                }
                int temp = Integer.parseInt(ip[i]);
                if(temp < 0 || temp > 255){
                    isC = false;
                    break;
                }
            }
            if(isC){
                counter.put("C", counter.get("C") + 1);
                // 检查一下是不是私有ip
                if(num == 192 && Integer.parseInt(ip[1]) == 168)
                    counter.put("private", counter.get("private") + 1);
            }else
                counter.put("Error", counter.get("Error") + 1);
        }else if(num >= 224 && num <= 239){
            // 检查是不是D类ip
            boolean isD = true;
            for(int i = 1; i < 4; i++){
                if(ip[i].length() == 0) {
                    isD = false;
                    break;
                }
                int temp = Integer.parseInt(ip[i]);
                if(temp < 0 || temp > 255){
                    isD = false;
                    break;
                }
            }
            if(isD)
                counter.put("D", counter.get("D") + 1);
            else
                counter.put("Error", counter.get("Error") + 1);
        }else if(num >= 240 && num <= 255){
            // 检查是不是E类ip
            boolean isE = true;
            for(int i = 1; i < 4; i++){
                if(ip[i].length() == 0) {
                    isE = false;
                    break;
                }
                int temp = Integer.parseInt(ip[i]);
                if(temp < 0 || temp > 255){
                    isE = false;
                    break;
                }
            }
            if(isE)
                counter.put("E", counter.get("E") + 1);
            else
                counter.put("Error", counter.get("Error") + 1);
        }else
            counter.put("Error", counter.get("Error") + 1);
    }
    
    private static boolean isRightMask(String[] mask){
        // 全0和全255都不是合法的掩码
        if(Integer.parseInt(mask[0]) == 0)
            return false;
        if(mask[0].equals("255") && mask[1].equals("255") && mask[2].equals("255") && mask[3].equals("255"))
            return false;
        for(int i = 0; i < mask.length; i++){
            if(mask[i].length() == 0) return false;
            int temp = Integer.parseInt(mask[i]);
            if(temp >= 0 && temp < 255){
                String binstr = Integer.toBinaryString(Integer.parseInt(mask[i]));
                for(int k = 0; k < 8 - binstr.length(); k++)
                    binstr = "0" + binstr;
                if(binstr.indexOf("01") != -1){
                    // 前面不是连续的1
                    return false;
                }else{
                    // 前面是连续的1,检查一下后面是不是都是0
                    for(int j = i + 1; j < mask.length; j++)
                        if(!mask[j].equals("0")) return false;
                    return true;
                }
            }else if(temp == 255)
                continue;
            else
                return false;
        }
        return true;
    }
}

发表于 2021-03-28 14:52:43 回复(0)
有点冗长,但觉得挺清晰的, 有个疑问是时间做不到1ms,不知道哪里耗时
#include<stdio.h>
#include<string.h>

#define calInt(a,b,c,d) (((a*256 + b)*256 + c)*256 + d)

unsigned int AMin = calInt(1,0,0,0);
unsigned int AMax = calInt(126,255,255,255);
unsigned int BMin = calInt(128,0,0,0);
unsigned int BMax = calInt(191,255,255,255);
unsigned int CMin = calInt(192,0,0,0);
unsigned int CMax = calInt(223,255,255,255);
unsigned int DMin = calInt(224,0,0,0);
unsigned int DMax = calInt(239,255,255,255);
unsigned int EMin = calInt(240,0,0,0);
unsigned int EMax = calInt(255,255,255,255);

unsigned int P1Min = calInt(10,0,0,0);
unsigned int P1Max = calInt(10,255,255,255);
unsigned int P2Min = calInt(172,16,0,0);
unsigned int P2Max = calInt(172,31,255,255);
unsigned int P3Min = calInt(192,168,0,0);
unsigned int P3Max = calInt(192,168,255,255);

unsigned int arr2int(unsigned int *arr)
{
    unsigned int i,ret = 0;

    for(i = 0; i < 4; i++)
    {
        ret *= 256;
        ret +=arr[i];
    }
    return ret;
}

int rangeValidate(unsigned int *arr)
{
    int i;

    for(i = 0; i < 4; i++)
    {
        if(arr[i] >= 256)
            return 0;
    }
    return 1;
}
int maskValidate(unsigned int mask)
{
    int c1 = 0;
    
    if(mask != 0 && mask != 0xFFFFFFFF)
    {   
        mask = ~mask;
        mask += 1;
        while(mask)
        {
            if( mask & 1)
                c1++;
            mask >>= 1;
        }
    }    
    return c1 == 1;
}

int main()
{
    unsigned int ip[4] = {0}, mask[4] = {0},intIp,intMask;
    int A=0,B=0,C=0,D=0,E=0,error=0,private=0,format = 0;

    while( ( format = scanf( "%d.%d.%d.%d~%d.%d.%d.%d", 
                      &ip[0],&ip[1],&ip[2],&ip[3],&mask[0],&mask[1],&mask[2],&mask[3]) ) != EOF)
    {
        if( format != 8 )
        {
            error++;
            while(getchar() != '\n');
            continue;
        }
        
        if( rangeValidate( ip ) && rangeValidate( mask ))
        {
            intIp = arr2int( ip );
            intMask = arr2int( mask );
            if( maskValidate( intMask ) )
            {
                if( intIp >= AMin && intIp <= AMax )
                    A++;
                if( intIp >= BMin && intIp <= BMax )
                    B++;
                if( intIp >= CMin && intIp <= CMax )
                    C++;
                if( intIp >= DMin && intIp <= DMax )
                    D++;
                if( intIp >= EMin && intIp <= EMax )
                    E++;
                
                if( ( intIp >= P1Min && intIp <= P1Max ) || 
                    ( intIp >= P2Min && intIp <= P2Max ) || 
                    ( intIp >= P3Min && intIp <= P3Max ) )
                    private++;
            }
            else
            {
                error++;
            }
        }
        else
        {
            error++;
        }
    }
    printf( "%d %d %d %d %d %d %d", A,B,C,D,E,error,private );
    return 0;
}

编辑于 2021-01-22 21:13:39 回复(0)
import java.util.*;
public class Main {
    public static final long[] boundA = new long[] {
            0x01000000L,
            0x7EFFFFFFL
    };
    public static final long[] boundB = new long[] {
            0x80000000L,
            0xBFFFFFFFL
    };
    public static final long[] boundC = new long[] {
            0xC0000000L,
            0xDFFFFFFFL
    };
    public static final long[] boundD = new long[] {
            0xE0000000L,
            0xEFFFFFFFL
    };
    public static final long[] boundE = new long[] {
            0xF0000000L,
            0xFFFFFFFFL
    };
    public static final long[][] ignored = new long[][] {
            new long[]{
                    0x00000000L,
                    0x00FFFFFFL
            },
            new long[] {
                    0x7F000000L,
                    0x7FFFFFFFL
            }
    };
    public static final long[][] boundPrivates = new long[][] {
            new long[] {
                    0x0A000000L,
                    0x0AFFFFFFL
            },
            new long[] {
                    0xAC0F0000L,
                    0xAC1F0000L
            },
            new long[] {
                    0xC0A80000L,
                    0xC0A8FFFFL
            }
    };
    public static final long[] validMasks = new long[] {
            (0xFFFFFFFFL << 1) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 2) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 3) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 4) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 5) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 6) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 7) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 8) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 9) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 10) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 11) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 12) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 13) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 14) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 15) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 16) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 17) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 18) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 19) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 20) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 21) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 22) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 23) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 24) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 25) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 26) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 27) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 28) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 29) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 30) & 0xFFFFFFFFL,
            (0xFFFFFFFFL << 31) & 0xFFFFFFFFL


    };
    public static boolean rightMask(String maskstr) {
        long mask = IP2Int(maskstr);
        if(mask == -1) {
            return false;
        }
        for(long i : validMasks) {
            if( i == mask) {
                return true;
            }
        }
        return false;
    }
    
    public static boolean isPrivate(String ipstr) {
        long ip = IP2Int(ipstr);
        return (ip >= boundPrivates[0][0] && ip <= boundPrivates[0][1]) ||
                (ip >= boundPrivates[1][0] && ip <= boundPrivates[1][1]) ||
                (ip >= boundPrivates[2][0] && ip <= boundPrivates[2][1]) ;
    }
    
    public static int getIPType(long ip) {
        if(ip >= boundA[0] && ip <= boundA[1]) {
            return 1;
        } else if(ip >= boundB[0] && ip <= boundB[1]) {
            return 2;
        } else if(ip >= boundC[0] && ip <= boundC[1]) {
            return 3;
        } else if(ip >= boundD[0] && ip <= boundD[1]) {
            return 4;
        } else if(ip >= boundE[0] && ip <= boundE[1]) {
            return 5;
        } else if((ip >= ignored[0][0] && ip <= ignored[0][1]) ||
                (ip >= ignored[1][0] && ip <= ignored[1][1])) {
            return -2;
        }
        else {
            return 6;
        }
    }
    public static long IP2Int(String str) {
        long result = -1;
        String[] split = str.split("\\.");
        if(split.length != 4) {
            return result;
        }
        result = 0;
        for(String part : split) {
            try {
                result = (result << 8 | Integer.parseInt(part));
            } catch (NumberFormatException ex) {
                ex.printStackTrace();
                result = -1;
                break;
            }
        }
        return result;
    }
    public static int identifyIP(String ipstr) {
        int err = 0;
        long ip = IP2Int(ipstr);
        if(ip == -1) {
            err = 6;
        } else {
            err = getIPType(ip);
        }

        return err;
    }

    public static void main(String[] args) {
        int A = 0; //1
        int B =0 ; //2
        int C = 0; //3
        int D = 0; //4
        int E = 0; //5
        int ERROR = 0; //6
        int PRIVATE = 0; //7
        Scanner sc = new Scanner(System.in);
        while(true) {
            String str;
            if(sc.hasNextLine()) {
                str = sc.nextLine();
            } else {
                break;
            }
            String[] split = str.split("~");
            String ip = split[0];
            String mask = split[1];
            if(!rightMask(mask)) {
                ERROR++;
            } else {
                int res = identifyIP(ip);
                switch(res) {
                    case 1: A++;break;
                    case 2: B++;break;
                    case 3: C++;break;
                    case 4: D++;break;
                    case 5: E++;break;
                    case 6: ERROR++;break;
                    default: break;
                }
                if(res != 6) {
                    if(isPrivate(ip)) {
                        PRIVATE++;
                    }
                }
            }  
        }
        System.out.printf("%d %d %d %d %d %d %d\n",A, B, C, D, E, ERROR, PRIVATE);
    }
}

引用一下注意的点
当子网掩码错误时,不在判断ip是否有效,错误直接加一, 进行下次循环
这个点第一次是没发现的
实际上如果把IP地址转化到uint32,这个题目就很简单了,不过java没有uint32,用long代替。
子网掩码直接使用穷举方法打表。
发表于 2020-09-26 18:13:45 回复(0)
def checkyanma(yanma01str):
    if yanma01str[0]=='0'&nbs***bsp;yanma01str[-1]=='1':
        return False
    ing = 1
    for c in yanma01str:
        if c=='1' and ing==0:
            return False
        if c=='0':
            ing=0
    return True

def checkip(iplist):
    kind, si = 5, 0
    for num in iplist:
        if num<0&nbs***bsp;num>255:
            return kind, si
    if 1<=iplist[0]<=126: kind = 0
    elif 128<=iplist[0]<=191: kind = 1
    elif 192<=iplist[0]<=223: kind = 2
    elif 224<=iplist[0]<=239: kind = 3
    else: kind = 4
    if iplist[0]==10: si = 1
    elif iplist[0]==172 and 16<=iplist[1]<=31: si = 1
    elif iplist[0]==192 and iplist[1]==168: si = 1
    return kind, si

def solution(record):
    ans = [0,0,0,0,0,0,0]
    for _ in record:
        ipstr, yanmastr = _[0], _[1]
        iplist = list(map(int, [x for x in ipstr.split('.') if x]))
        yanmalist = list(map(int, [x for x in yanmastr.split('.') if x]))
        if len(iplist)!=4:
            ans[5] += 1
            continue
        
        if len(yanmalist)!=4:
            ans[5] += 1
            continue
        yanma01str = ''.join(list(map(lambda x:bin(x)[2:].rjust(8, '0'), yanmalist)))
        if not checkyanma(yanma01str):
            ans[5] += 1
            continue
        # 排除0和127开头
        if iplist[0]==0&nbs***bsp;iplist[0]==127: continue
        kind, si = checkip(iplist)
        ans[kind]+=1
        ans[-1]+=si
    return ' '.join(list(map(str, ans)))

import sys
while True:
    try:
        record = []
        #while True:
        for line in sys.stdin:
            # inputlist = sys.stdin.readline()
            # inputlist = input()
            # if inputlist=='':
             #     break
            record.append(list(line.split('~')))
        if record==[]:
            break
        else:
            print(solution(record))
    except:
        break

最坑的就是127的时候直接跳过,但掩码错了其实不能跳过,要错误加一的。
输入也不能用input,像这种没有制定输入多少行的要用for line in sys.stdin:


发表于 2020-08-18 11:42:07 回复(2)
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <string>
//使用网络库函数判断 ip是否合规    --    学到了
//1、使用fgets函数读入一行数据
//2、对每一行数据进行按照~切割成 ip 和子网掩码
//3、判断子网掩码(本题是 不能全1,且前面是连续的1后面是连续的0),则可以用子网掩码取反+1,则二进制只有一个1个1
//处理过的子网掩码再和处理过的子网掩码-1做与操作,若为0 则子网掩码ok
//4、判断ip的范围,来进行相应的变量计数即可


using namespace std;

int validmask(char * mask)
{
    unsigned int n[4],res = 0;
    int i ;
    sscanf(mask,"%u.%u.%u.%u",&n[3],&n[2],&n[1],&n[0]);
    if(n[3] == 255 && n[2] == 255 && n[1] == 255 && n[0]== 255)
        return 0;
    for(i = 0;i<4;i++)
    {
        res += n[i]<<(i*8);
    }
    res = ~res +1;
    if((res & (res - 1)) == 0)    return 1;
    return 0;
}

int main()
{
    char str[50];
    int a = 0,b=0,c=0,d=0,e=0,err=0,pri=0;
    while(fgets(str,50,stdin))
    {
        char *p = str;
        char ip[2][20];
        int i = 0;
        int maskflag = 0;
        while((p = strtok(p,"~") )!= NULL)
        {
            strcpy(ip[i],p);
            i++;
            p = NULL;
            if(i == 2)    i=0;
        }
        maskflag = validmask(ip[1]);
        if(maskflag)
        {
            struct in_addr st;
            unsigned int ip1,ip2;
            int valid = inet_pton(AF_INET,ip[0],(void *)&st);
            sscanf(ip[0],"%u.%u",&ip1,&ip2);
            if(valid)
            {
                if(ip1>=1 && ip1 <=126)
                    a++;
                else if(ip1>=128 && ip1 <=191)
                    b++;
                else if(ip1>=192 && ip1 <=223)
                    c++;
                else if(ip1>=224 && ip1 <=239)
                    d++;
                else if(ip1>=240 && ip1 <=255)
                    e++;
                if(ip1==10
                        || (ip1==172 && ip2 >=16 &&ip2 <=31)
                        || (ip1==192 && ip2 ==168))
                    pri ++;
            }else
                err++;
        }else
        {
            err++;
        }
    }
    cout<<a<<" "<<b<<" "<<c<<" "<<d<<" "<<e<<" "<<err<<" "<<pri<<endl;
}

发表于 2020-07-14 11:28:16 回复(0)
import re
import sys


def is_legal_ip(ip):
    if not ip:
        return False

    pattern = re.compile(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
    if not pattern.match(ip):
        return False

    segments = ip.split(".")
    for s in segments:
        s = int(s)
        if s < 0&nbs***bsp;s > 255:
            return False

    return True


def is_private_ip(ip):
    if not is_legal_ip(ip):
        return False

    segments = ip.split(".")
    s0 = int(segments[0])
    s1 = int(segments[1])
    if s0 == 10:
        return True
    if s0 == 172:
        if 16 <= s1 <= 31:
            return True
    if s0 == 192 and s1 == 168:
        return True

    return False


def is_legal_mask(mask):
    if not is_legal_ip(mask):
        return False

    bin_mask = "".join(
        [format(int(segment), 'b').zfill(8) for segment in mask.split(".")])
    first_zero_idx = bin_mask.find("0")
    last_one_idx = bin_mask.rfind("1")
    if first_zero_idx == -1&nbs***bsp;last_one_idx == -1:
        return False
    if last_one_idx > first_zero_idx:
        return False
    return True


def ip_category(ip):
    if not is_legal_ip(ip):
        raise ValueError("Illegal IP")

    s0 = int(ip.split(".")[0])
    if 1 <= s0 <= 126:
        return "A"
    if 128 <= s0 <= 191:
        return "B"
    if 192 <= s0 <= 223:
        return "C"
    if 224 <= s0 <= 239:
        return "D"
    if 240 <= s0 <= 255:
        return "E"

    raise ValueError("Unknown category")


if __name__ == "__main__":
    a = 0
    b = 0
    c = 0
    d = 0
    e = 0
    f = 0
    p = 0
    for line in sys.stdin:
        ip, mask = line.strip().split("~")
        if not is_legal_ip(ip)&nbs***bsp;not is_legal_mask(mask):
            f += 1
        else:
            if is_private_ip(ip):
                p += 1
            try:
                category = ip_category(ip)
                if category == "A":
                    a += 1
                if category == "B":
                    b += 1
                if category == "C":
                    c += 1
                if category == "D":
                    d += 1
                if category == "E":
                    e += 1
            except ValueError:
                pass
    print(a, b, c, d, e, f, p)

发表于 2020-07-14 10:19:40 回复(0)
错误提示没有输入输出数据的问题该怎么解决?
发表于 2020-05-04 18:06:02 回复(0)
import java.util.Scanner;

public class Main{
    public static int pr;
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int A=0,B=0,C=0,E=0,D=0,error=0;
        while(sc.hasNext()){
            String s=sc.nextLine();
            String sArr[]=s.split("~");
            if(panduanyanma(sArr[1])){
                char k=pandan***(sArr[0],sArr[1]);
                if(k=='A'){A++;}else if(k=='B'){B++;}else if(k=='C'){C++;}
                else if(k=='D'){D++;}else if(k=='E'){E++;}
                else if(k=='n'){error++;}else{;}
                
            }else{
                error++;
            }
        }
        System.out.println(A+" "+B+" "+C+" "+D+" "+E+" "+error+" "+pr);
    }
    public static boolean panduanyanma(String s){
        String sArr[]=s.split("\\.");
        int k[]=new int [sArr.length];
        for(int i=0;i<sArr.length;i++){
            //System.out.println(sArr[i].length()>3);
            if(sArr[i].length()<=0||sArr[i].length()>3)
            {  return false;}
            k[i]=Integer.parseInt(sArr[i]);
            //System.out.println(k[i]);
           if(k[i]>255)return false;
           if(i>0&&k[i-1]!=255&&k[i]!=0)return false;
           if(i>0&&(k[i-1]==255)&&(k[i]!=0&&k[i]!=128&&k[i]!=192&&k[i]!=224&&k[i]!=240&&k[i]!=248&&k[i]!=252&&k[i]!=254&&k[i]!=255))
           { return false;}
           if(i==sArr.length-1&&k[i]==255)return false;

        }
        return true;
    }
    public static char pandan***(String s,String d){
        String sArr[]=s.split("\\.");
        int k[]=new int [sArr.length];
        String dArr[]=d.split("\\.");
        int kd[]=new int [dArr.length];
        for(int i=0;i<sArr.length;i++){
            //System.out.println(sArr[i].length()>3);
            if(sArr[i].length()<=0||sArr[i].length()>3)
            {  return 'n';}
            k[i]=Integer.parseInt(sArr[i]);
            kd[i]=Integer.parseInt(dArr[i]);
            if(k[i]>255)return 'n';
            
            k[i]=k[i]&kd[i];
            
                
            
        }
        if(k[0]==10&&k[1]>=0&&k[2]>=0&&k[3]>=0&&k[1]<=255&&k[2]<=255&&k[3]<=255){
            pr++;
        }
        if(k[0]==172&&k[1]>=16&&k[2]>=0&&k[3]>=0&&k[1]<=31&&k[2]<=255&&k[3]<=255){
            pr++;
        }
        if(k[0]==192&&k[1]==168&&k[2]>=0&&k[3]>=0&&k[2]<=255&&k[3]<=255){
            pr++;
            
        }
        if(k[0]>=1&&k[0]<=126&&k[1]>=0&&k[2]>=0&&k[3]>=0&&k[1]<=255&&k[2]<=255&&k[3]<=255){
            return 'A';
        }
        if(k[0]>=128&&k[0]<=191&&k[1]>=0&&k[2]>=0&&k[3]>=0&&k[1]<=255&&k[2]<=255&&k[3]<=255){
            return 'B';
        }
        if(k[0]>=192&&k[0]<=223&&k[1]>=0&&k[2]>=0&&k[3]>=0&&k[1]<=255&&k[2]<=255&&k[3]<=255){
            return 'C';
        }
        if(k[0]>=224&&k[0]<=239&&k[1]>=0&&k[2]>=0&&k[3]>=0&&k[1]<=255&&k[2]<=255&&k[3]<=255){
            return 'D';
        }
        if(k[0]>=240&&k[0]<=255&&k[1]>=0&&k[2]>=0&&k[3]>=0&&k[1]<=255&&k[2]<=255&&k[3]<=255){
            return 'E';
        }
        return 'o';
    }
}
使用两个方法,一个是判断子网掩码是否符合要求,其符合才会去考虑ip地址。如果子网掩码不符合,那么ip地址就也算错误,不做考虑。另一个方法是判断地址是否符合,这里面直接做与,然后判断每一个数字对应的是哪个地址段。
发表于 2020-04-29 23:13:17 回复(0)
c语言版
#include <stdio.h>
#include <string.h>
int main(){
	char s[20];
	int i,j,len,a=0,b=0,c=0,d=0,e=0,err=0,pri=0,flag=0,num=0,p=0,ip[8];
	bool error,fg;
	while(scanf("%s",s)!=EOF){
		p=0;flag=0;error=false;fg=false;//p指向ip[p],flag标记数字字符起始位置,error判断输入是否有错误,fg子网掩码是否正确
		len=strlen(s);
		for(i=0;i<len+1;i++){   //提起输入字符串里的数字并且判断输入格式是否正确
				if(s[i]>='0'&&s[i]<='9')
					continue;
				else if(s[i]=='.'||s[i]=='~'||s[i]=='\0'){
					num=0;
					for(j=flag;j<i;j++)
						num=num*10+(s[j]-'0');
					ip[p++]=num;
					flag=i+1;
					if(num<0||num>255){
						err++;
						error=true;     //格式错误
						break;
					}
					if(s[i]!='\0')
					if(s[flag]<'0'||s[flag]>'9'){
						err++;
						error=true;
						break;
					}
				}
				else{
					err++;
					error=true;
					break;
				}
		}
		if(!error){
			num=0;
			if(ip[4]==0||ip[7]==255)  //判断子网掩码是否正确
				err++;
			else{
				for(i=4;i<=7;i++){
					if(ip[i]==255)
						continue;
					for(j=i+1;j<=7;j++)
						num+=ip[j];
					if((ip[i]==254||ip[i]==252||ip[i]==248||ip[i]==240||ip[i]==224||ip[i]==192||ip[i]==128||ip[i]==0)&&num==0)
						fg=true;   //子网掩码正确
						else
						err++;
					break;
				}
			}
			if(fg){  //子网掩码正确的情况下判断是哪一类ip
				if(ip[0]>=1&&ip[0]<=126) a++;
				else if(ip[0]>=128&&ip[0]<=191) b++;
				else if(ip[0]>=192&&ip[0]<=223) c++;
				else if(ip[0]>=224&&ip[0]<=239) d++;
				else if(ip[0]>=240&&ip[0]<=255) e++;
				if(ip[0]==10||(ip[0]==172&&ip[1]>=16&&ip[1]<=31)||(ip[0]==192&&ip[1]==168))
					pri++;
			}
		}
	}
	printf("%d %d %d %d %d %d %d\n",a,b,c,d,e,err,pri);
	return 0;
}

发表于 2020-02-11 17:44:22 回复(0)
import java.util.Scanner;

/**
 * @author sunlichao
 * @date 2019/12/29
 */
public class Main {

    public static long ipToInt(String ip) {
        String[] p = ip.split("\\.");
        if (p.length < 4) {
            return -1;
        }
        long result = 0;
        try {
            for (int i = 0; i < 4; i++) {
                long t = Integer.parseInt(p[i]);
                if (t < 0 || t > 255) {
                    return -1;
                }
                result |= (t << (8 * (3 - i)));
            }
        } catch (NumberFormatException ex) {
            return -1;
        }

        return result;
    }

    public static boolean validMask(String mask) {
        long a = 0L;
        long r = ipToInt(mask);

        int m = (int) r;
        if (m == -1) {
            return false;
        }
        while ((m <<= 1) < 0) {
        }

        if (m == 0) {
            return true;
        } else {
            return false;
        }

    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long[][] data = {
                {ipToInt("1.0.0.0"), ipToInt("126.255.255.255")},
                {ipToInt("128.0.0.0"), ipToInt("191.255.255.255")},
                {ipToInt("192.0.0.0"), ipToInt("223.255.255.255")},
                {ipToInt("224.0.0.0"), ipToInt("239.255.255.255")},
                {ipToInt("240.0.0.0"), ipToInt("255.255.255.255")},
        };
        long[][] personal = {
                {ipToInt("10.0.0.0"), ipToInt("10.255.255.255")},
                {ipToInt("172.16.0.0"), ipToInt("172.31.255.255")},
                {ipToInt("192.168.0.0"), ipToInt("192.168.255.255")},
        };

        int[] abcd = new int[5];
        int wrongIp = 0;
        int tmp;
        int personalCount = 0;
        while (scanner.hasNext()) {
            String line = scanner.nextLine();
            String[] pre = line.split("~");
            long ip = ipToInt(pre[0]);

            if (!validMask(pre[1])) {
                wrongIp++;
            } else {
                if (ip != -1) {
                    for (int i = 0; i < data.length; i++) {
                        if (ip >= data[i][0] && ip <= data[i][1]) {
                            abcd[i]++;
                            break;
                        }
                    }
                } else {
                    wrongIp++;
                }


                for (int i = 0; i < personal.length; i++) {
                    if (ip >= personal[i][0] && ip <= personal[i][1]) {
                        personalCount++;
                        break;
                    }
                }
            }
        }

        System.out.println(abcd[0] + " " + abcd[1] + " " + abcd[2] + " " + abcd[3] + " " + abcd[4] + " " + wrongIp + " " + personalCount);
    }
}


编辑于 2019-12-30 01:44:43 回复(2)
先说几个坑:
  1. 按题意掩码255.255.255.255是错误的,实际应是正确,至少有30%的测试集包含这一掩码;
  2. 掩码和IP同时错误只计一次
  3. 非A/B/C/D/E的非法IP不算错误,竟然有60%的测试集包含这样的IP,残念;
这个题的测试集并不好,建议修改一下,完全判断的代码只能10%AC也是醉了。
整体思路
其实题意比较简单,按部就班就好:判断字符格式 -> 判断掩码值 -> 判断IP种类并累加
代码思路
  • 判断掩码正确性可以将掩码转换为32位无符号数后,计算掩码的非。把问题转化为判断是否从低位开始是连续的1。该问题又等价于判断数字是否为2n-1,可以用 `x & (x + 1) == 0` 来判断;
  • 判断IP用分治法应该是可以的,但我比较习惯转换为32位数之后直接比较,判断是否在范围内只需比较两次;
  • 判断字符格式用正则可能是最方便的,C++不能用Boost真的伤= =差点就用python写了。
其他细节看代码吧,注释少了点不过重要的点我上面都写了。
#include <bits/stdc++.h>

size_t countNum[7];

unsigned int transformIP(std::string _IP) noexcept(false) {
    unsigned char data[4];
    std::string str[4];
    memset(data, 0, sizeof(data));

    for(size_t i = 0; i < 3; i++) {
        auto pos = _IP.find('.');
        if(pos == std::string::npos || pos == 0)
            throw std::string("error");
        str[i] = _IP.substr(0, pos);
        _IP = _IP.substr(pos + 1);
    }
    if(_IP.empty())throw std::string("error");
    str[3] = _IP;
    for(size_t i = 0; i < 4; i++) {
        for(const char ch : str[i]) {
            if(ch < '0' || ch > '9')
                throw std::string("error");
            data[i] *= 10;
            data[i] += ch - '0';
        }
        if(data[i] > 255)throw std::string("error");
    }
    return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
}

void processLine(const std::string& _Line) {
    auto pos = _Line.find('~');
    if(pos == std::string::npos) {
        countNum[5]++;    // wrong line
        return;
    }
    std::string mask = _Line.substr(pos + 1);
    std::string ip = _Line.substr(0, pos);
    try {
        unsigned int ipVal = transformIP(ip);
        unsigned int maskVal = transformIP(mask);
        unsigned int tmp = ~maskVal;
//        if(tmp & (tmp + 1)) {    // 255.255.255.255 is actually valid
        if(!tmp || tmp & (tmp + 1)) {
            countNum[5]++;    // wrong mask
            return;
        }
        static constexpr unsigned int A_BEGIN = 1u << 24;
        static constexpr unsigned int A_END = (127u << 24) - 1u;
        static constexpr unsigned int B_BEGIN = 128u << 24;
        static constexpr unsigned int B_END = (192u << 24) - 1u;
        static constexpr unsigned int C_BEGIN = 192u << 24;
        static constexpr unsigned int C_END = (224u << 24) - 1u;
        static constexpr unsigned int D_BEGIN = 224u << 24;
        static constexpr unsigned int D_END = (240u << 24) - 1u;
        static constexpr unsigned int E_BEGIN = 240u << 24;
        static constexpr unsigned int E_END = 0xFFFFFFFFu;
        static constexpr unsigned int SP1_BEGIN = 10u << 24;
        static constexpr unsigned int SP1_END = (11u << 24) - 1u;
        static constexpr unsigned int SP2_BEGIN = (172u << 24) | (16u << 16);
        static constexpr unsigned int SP2_END = ((172u << 24) | (32u << 16)) - 1u;
        static constexpr unsigned int SP3_BEGIN = (192u << 24) | (168u << 16);
        static constexpr unsigned int SP3_END = ((192u << 24) | (169u << 16)) - 1u;

        if(ipVal >= A_BEGIN && ipVal <= A_END) {
            countNum[0]++;
            if(ipVal >= SP1_BEGIN && ipVal <= SP1_END) {
                countNum[6]++;
            }
        } else if(ipVal >= B_BEGIN && ipVal <= B_END) {
            countNum[1]++;
            if(ipVal >= SP2_BEGIN && ipVal <= SP2_END) {
                countNum[6]++;
            }
        } else if(ipVal >= C_BEGIN && ipVal <= C_END) {
            countNum[2]++;
            if(ipVal >= SP3_BEGIN && ipVal <= SP3_END) {
                countNum[6]++;
            }
        } else if(ipVal >= D_BEGIN && ipVal <= D_END) {
            countNum[3]++;
        } else if(ipVal >= E_BEGIN && ipVal <= E_END) {
            countNum[4]++;
        } /* else {
            std::cout << _Line << " is invalid!" << std::endl;
            countNum[5]++;
        } */
        return;
    } catch(std::string& ex) {
        countNum[5]++;    // wrong format
        return;
    }
}

int main(int argc, const char* argv[]) {
    std::ios::sync_with_stdio(false);

    std::string buffer;
    while(std::cin >> buffer) {
        processLine(buffer);
    }
    std::cout << countNum[0];
    for(size_t i = 1; i < 7; i++)
        std::cout << ' ' << countNum[i];

    return EXIT_SUCCESS;
}


编辑于 2019-08-28 14:16:18 回复(1)
这题主要涉及到字符串分隔、转换,判断有效的IP和掩码等,注意的坑:这私网IP10.0.0.0~10.255.255.255属于A类地址。我觉得我的掩码判断做的比较好,从最低位的0开始判断,简单高效,需要注意的是255.255.255.255这个错误的子网掩码要单独判断。

#include<iostream>
#include<string>
#include<vector>

using namespace std;

void splitString(const string& str, const string separator, vector<string>& res)
{
    int pos1, pos2;
    pos1 = 0;
    pos2 = str.find(separator, pos1);
    string temp;
    while (pos1 != pos2)
    {
        temp = str.substr(pos1, pos2 - pos1);
        res.push_back(temp);
        pos1 = pos2 + 1;
        if (pos1 == 0)break;
        pos2 = str.find(separator, pos1);
    }
}

bool checkIpNums(const vector<int>& ips)
{
    if (ips.size() == 4)
    {
        if (ips[0] >=0 && ips[0] <= 255 && ips[1] >=0 && ips[1] <= 255
            && ips[2] >=0 && ips[2] <= 255 && ips[3] >= 0 && ips[3] <= 255)
            return true;
        else
            return false;
    }
    else
        return false;
}

bool validMask(const vector<int>& mask)
{
    if (checkIpNums(mask))
    {
        int pos=3;
        for (int i = 3; i >= 0; i--)
        {
            if (mask[i] != 0)
            {
                pos = i;
                break;
            }
        }
        
        if (pos == 3&&mask[pos]==255)return false;
        
        if (mask[pos] == 255 || mask[pos] == 254 || mask[pos] == 252 || mask[pos] == 248 ||
            mask[pos] == 240 || mask[pos] == 224 || mask[pos] == 192 || mask[pos] == 128)
        {
            int tag = 0;
            while (pos >0)
            {
                pos--;
                if (mask[pos] != 255)
                {
                    tag = 1;
                    break;
                }
            }
            if (tag == 0)return true;
            else return false;
        }
        else return false;
    }
    else
        return false;
}

int main()
{
    string str;
    int A, B, C, D, E, errIpMask, privateIP;
    A = B = C = D = E = errIpMask = privateIP = 0;
    while(getline(cin, str))
    {
        vector<string> tempSepStr, ipStr, maskStr;
        vector<int> ip, mask;
        splitString(str, "~", tempSepStr);
        splitString(tempSepStr[0], ".", ipStr);
        splitString(tempSepStr[1], ".", maskStr);
        for (int i = 0; i < ipStr.size(); i++)
        {
            ip.push_back(stoi(ipStr[i]));
        }
        for (int i = 0; i < maskStr.size(); i++)
        {
            mask.push_back(stoi(maskStr[i]));
        }

        if (validMask(mask)&&checkIpNums(ip))
        {
                if (ip[0] >= 1 && ip[0] <= 126)
                {
                    if (ip[0] == 10)privateIP++;
                    A++;
                }

                if (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31)privateIP++;
                if (ip[0] == 192 && ip[1] == 168)privateIP++;

                if (ip[0] >= 128 && ip[0] <= 191) B++;

                if (ip[0] >= 192 && ip[0] <= 223) C++;

                if (ip[0] >= 224 && ip[0] <= 239) D++;

                if (ip[0] >= 240 && ip[0] <= 255) E++;
        }
        else
            errIpMask++;
    }
    
    cout << A << " " << B << " " << C << " " << D << " " << E 
        << " " << errIpMask << " " << privateIP << endl;
    system("pause");
    return 0;
}

发表于 2019-03-30 11:42:36 回复(0)
//牛客有BUG,C++提交格式不对,将就看吧!
//判断子网掩码那部分可以参考
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int numberOf1(int n)
//计算二进制串中1的个数,用于辅助判断子网掩码是否合格
{
    int count = 0;
    while (n)
    {
        ++count;
        n = (n - 1)&n;
    }
    return count;
}
int main()
{
    int AA = 0;
    int BB = 0;
    int CC = 0;
    int DD = 0;
    int EE = 0;
    int Error = 0;
    int privateIP = 0;
    string str;
    while (getline(cin, str))
    {

        int numOfDot = 0;
        int numOfTilde = 0;
        vector<int> indexOfDot;
        vector<int> indexOfTilde;
        for (int i = 0; i < str.size(); i++)
        {
            if (str[i] == '.')
            {
                numOfDot++;
                indexOfDot.push_back(i);
            }
            if (str[i] == '~')
            {
                numOfTilde++;
                indexOfTilde.push_back(i);
            }
        }
        //先查格式:是否满足有六个.和一个~
        if (numOfDot != 6 || numOfTilde != 1)
        {
            Error++;
            continue;
        }
        string ip1 = str.substr(0, indexOfDot[0]);
        string ip2 = str.substr(indexOfDot[0] + 1, indexOfDot[1] - indexOfDot[0] - 1);
        string ip3 = str.substr(indexOfDot[1] + 1, indexOfDot[2] - indexOfDot[1] - 1);
        string ip4 = str.substr(indexOfDot[2] + 1, indexOfTilde[0] - indexOfDot[2] - 1);
        string mask1 = str.substr(indexOfTilde[0] + 1, indexOfDot[3] - indexOfTilde[0] - 1);
        string mask2 = str.substr(indexOfDot[3] + 1, indexOfDot[4] - indexOfDot[3] - 1);
        string mask3 = str.substr(indexOfDot[4] + 1, indexOfDot[5] - indexOfDot[4] - 1);
        string mask4 = str.substr(indexOfDot[5] + 1, str.size() - indexOfDot[5] - 1);
        int IP1 = stoi(ip1);
        int IP2 = stoi(ip2);
        int IP3 = stoi(ip3);
        int IP4 = stoi(ip4);
        //第二查:IP地址是否在0-255之间
        if ((IP1 < 0 || IP1 > 255) || (IP2 < 0 || IP2 > 255) || 
            (IP3 < 0 || IP3 > 255) || (IP4 < 0 || IP4 > 255))
        {
            Error++;
            continue;
        }
        int MASK1 = stoi(mask1);
        int MASK2 = stoi(mask2);
        int MASK3 = stoi(mask3);
        int MASK4 = stoi(mask4);
        //第三查:子网掩码是否在0-255之间,特别注意最后一位掩码不能是255
        if ((MASK1 < 0 || MASK1 > 255) || (MASK2 < 0 || MASK2 > 255) || 
            (MASK3 < 0 || MASK3 > 255) || (MASK4 < 0 || MASK4 >= 255))
        {
            Error++;
            continue;
        }
        //用二进制位***作的方法,判断一个串是否满足1111...00的模式
        unsigned long long bigIpNumber = 
            MASK1 * (1<<24) + MASK2 * (1<<16) + MASK3 * (1<<8) + MASK4;
        if (numberOf1((~bigIpNumber) + 1) != 1)//子网掩码不合格
        {
            Error++;
            continue;
        }
        //统计ABCDE类地址
        if ((IP1 >= 0 && IP1 <= 255) && (IP2 >= 0 && IP2 <= 255) && 
            (IP3 >= 0 && IP3 <= 255) && (IP4 >= 0 && IP4 <= 255))
        {
            if (IP1 >= 1 && IP1 <= 126)
                AA++;
            else if (IP1 >= 128 && IP1 <= 191)
                BB++;
            else if (IP1 >= 192 && IP1 <= 223)
                CC++;
            else if (IP1 >= 224 && IP1 <= 239)
                DD++;
            else if(IP1 >= 240 && IP1 <= 255)
                EE++;
        }
        else
        {
            Error++;
            continue;
        }
        //统计私有地址
        if (IP1 == 10)
            privateIP++;
        else if (IP1 == 172 && (IP2 >= 16 && IP2 <= 31))
            privateIP++;
        else if (IP1 == 192 && IP2 == 168)
            privateIP++;
    }
    cout << AA << " ";
    cout << BB << " ";
    cout << CC << " ";
    cout << DD << " ";
    cout << EE << " ";
    cout << Error << " ";
    cout << privateIP << endl;
}

编辑于 2018-09-22 21:54:49 回复(0)
#include<iostream>
#include<string>
#include<sstream>
#include<vector>
using namespace std;

unsigned int A[2] = {0x01000000,0x7EFFFFFF}; //A类网地址范围
unsigned int B[2] = {0x80000000,0xBFFFFFFF}; //B类网地址范围
unsigned int C[2] = {0xC0000000,0xDFFFFFFF}; //C类网地址范围
unsigned int D[2] = {0xE0000000,0xEFFFFFFF}; //D类网地址范围
unsigned int E[2] = {0xF0000000,0xFFFFFFFF}; //E类网地址范围
unsigned int F[2] = {0x0A000000,0x0AFFFFFF}; //私网地址范围1
unsigned int G[2] = {0xAC100000,0xAC1FFFFF}; //私网地址范围2
unsigned int H[2] = {0xC0A80000,0xC0A8FFFF}; //私网地址范围3

//将地址/掩码转换为unsigned int
unsigned int string2int(string str)
{
    int io = 0;
    unsigned int mas = 0;
    while((int)(str.find('.',io))>=0)
    {
        int i = str.find('.',io);
        if(i-io==0)
            return 0;
        istringstream ss;
        ss.str(str.substr(io,i-io));
        io = i+1;
        unsigned int temp;
        ss>>temp;
        mas<<=8;
        mas|=temp;
    }
    istringstream ss;
    ss.str(str.substr(io));
    unsigned int temp;
    ss>>temp;
    mas<<=8;
    mas|=temp;
    return mas;
}
//检查掩码是否合法
bool checkmask(unsigned int mas)
{
    //255.255.255.255的掩码的非法的
    if(mas==0xFFFFFFFF)
        return false;
    unsigned int flag = 1;
    while(flag!=0)
    {
        if((mas&flag)==0)
        {
            flag<<=1;
            continue;
        }
        else 
        {
            while(flag!=0)
            {
                if((mas&flag)==0)
                    return false;
                flag<<=1;
            }
        }
    }
    return true;
}
//寻找IP的类别
int checkipad(unsigned int ipa)
{
    if(ipa>=A[0]&&ipa<=A[1])
    {
        if(ipa>=F[0]&&ipa<=F[1])
            return 11;
        return 1;
    }
    else if(ipa>=B[0]&&ipa<=B[1])
    {
        if(ipa>=G[0]&&ipa<=G[1])
            return 12;
        return 2;
    }
    else if(ipa>=C[0]&&ipa<=C[1])
    {
        if(ipa>=H[0]&&ipa<=H[1])
            return 13;
        return 3;
    }
    else if(ipa>=D[0]&&ipa<=D[1])
        return 4;
    else if(ipa>=E[0]&&ipa<=E[1])
        return 5;
    return 0;
}
//主函数
int main()
{
    string str;
    vector<string> ipad;
    vector<string> mask;
    vector<int> res(7,0);
    while(getline(cin,str))
    {
        int pos = str.find('~');
        ipad.push_back(str.substr(0,pos));
        mask.push_back(str.substr(pos+1));
    }
    {
        unsigned int i;
        vector<int> ip;
        vector<int> im;
        for(i=0;i<ipad.size();++i)
        {
            unsigned int tep = string2int(ipad[i]);
            unsigned int tem = string2int(mask[i]);
            if(tep==0||tem==0)
            {
                res[5] += 1;
                continue;
            }
            else
            {
                int bop = checkipad(tep);
                bool bom = checkmask(tem);
                if(!bom)
                {
                    res[5] += 1;
                    continue;
                }
                else
                {
                    switch(bop)
                    {
                    case 1:
                        res[0] += 1;
                        break;
                    case 2:
                        res[1] += 1;
                        break;
                    case 3:
                        res[2] += 1;
                        break;
                    case 4:
                        res[3] += 1;
                        break;
                    case 5:
                        res[4] += 1;
                        break;
                    case 11:
                        res[0] += 1;
                        res[6] += 1;
                        break;
                    case 12:
                        res[1] += 1;
                        res[6] += 1;
                        break;
                    case 13:
                        res[2] += 1;
                        res[6] += 1;
                        break;
                    }
                }
            }
        }
    }
    unsigned int i;
    for(i=0;i<res.size();++i)
    {
        cout<<res[i];
        if(i<res.size()-1)
            cout<<' ';
    }
    cout<<endl;
    return 0;
}

编辑于 2018-08-06 22:53:20 回复(0)
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
 
using namespace std;
vector<string> split(string str,char del)
{
    stringstream ss(str);
    string tok;
    vector<string> ret;
    while(getline(ss,tok,del))
    {
        if(tok > "")
            ret.push_back(tok);
    }
    return ret;
}
 
int main()
{
    string all;
    int result[7]={0};
    while(getline(cin,all))
    {
        vector<string> ipyanma;
        ipyanma = split(all,'~');
        vector<string> ip,yanma;
        ip = split(ipyanma[0],'.');
        yanma = split(ipyanma[1],'.');
        unsigned int yyy=0,yuan=0,flag=0;
        if(ip.size() == 4 && yanma.size() == 4)
        {
            for(int kk=0;kk<4;kk++)
            {
                unsigned int temp11= atoi(yanma[kk].c_str());
                yyy += temp11 << ((3-kk)*8);
            }
            yuan = yyy;
            yyy = (~yyy) +1;
            flag = yyy & (yyy-1);
            if((flag ==0) && (yuan != 0xffffffff) && (yuan != 0) )
            {
                if(atoi(ip[0].c_str()) >= 1 && atoi(ip[0].c_str()) <= 126)
                    result[0] += 1;
                if(atoi(ip[0].c_str())>=128 && atoi(ip[0].c_str())<=191)
                    result[1] += 1;
                if(atoi(ip[0].c_str())>=192 && atoi(ip[0].c_str())<=223)
                    result[2] += 1;
                if(atoi(ip[0].c_str())>=224 && atoi(ip[0].c_str())<=239)
                    result[3] += 1;
                if(atoi(ip[0].c_str())>=240 && atoi(ip[0].c_str())<=255)
                    result[4] += 1;
                if((atoi(ip[0].c_str())>=10 && atoi(ip[0].c_str())<=10) ||
                   (atoi(ip[0].c_str())>=172 && atoi(ip[1].c_str())>=16 && 
                    atoi(ip[0].c_str())<=172 && atoi(ip[1].c_str())<=31) || 
                   (atoi(ip[0].c_str())>=192 && atoi(ip[1].c_str())>=168 && 
                    atoi(ip[0].c_str())<=192 && atoi(ip[1].c_str())<=168))
                    result[6] += 1;
            }
            else
            {
                result[5] += 1;
            }
        }
        else
        {
            result[5] += 1;
        }
    }
    cout<<result[0]<<" "<<result[1]<<" "<<result[2]<<" "<<result[3]<<" "<<result[4]<<" "<<result[5]<<" "<<result[6]<<endl;
    return 0;
}

发表于 2018-06-18 17:26:01 回复(0)