解题思路:
这题重头任务是判断IP地址和掩码输入是否合法,需要检查:
(1)有无其他字符乱入
(2)"."和"~"的数量和相对位置是否正确
(3)数字的个数及相对位置是否正确
(4)每个数字的范围是不是在[0,255]
(5)掩码是否合法(前面是连续的1,然后全是0)
(6)0.0.0.0和255.255.255.255也是非法掩码
IP和掩码下输入合法的情况下,分类就很简单了。
注意问题:
多种不合法输入出现,只算一次不合法
移位操作的结果(整型254<<1是508而不是252,因为整型为32位,1的个数没有减少;char型254<<1是-4而不是252,因为代表有符号数)
难点:
边判断格式合法否边提取子段数字
#include <iostream>
#include <string>
using namespace std;
int ip[4];
int mask[4];
bool Valid(string s){
int dotX=0; // "."的下标
int numX=0; // 数字的下标
int signX=s.find("~"); //记录"~"的下标
string subs; //IP地址记录子段
int i;
int num; //每个子段的数字大小
if(s.find_first_not_of("0123456789.~")!=string::npos) //有"0123456789.~"以外的字符,格式错误
return false;
if(signX==string::npos) //没有"~",格式错误
return false;
if(s.rfind(".")==s.size()-1) //如果最后一位是"."
return false;
for(i=0;i<7;i++){
dotX=s.find(".",numX);
if(dotX-numX==0) //两个"."之间没有数字,格式错误
return false;
if(dotX==string::npos) //少于6个".",格式错误
return false;
if(i==2 && (signX-dotX>4 || signX-dotX<2))
return false; //"~"和第三个"."之间不是1~3位数字,格式错误
if(i==3 && (dotX-signX>4 || dotX-signX<2))
return false; //第四个"."和"~"之间不是1~3位数字,格式错误
if(i==3){ //第三次循环取"."和"~"之间的数
subs=s.substr(numX,signX-numX);
numX=signX+1;
}
else{
subs=s.substr(numX,dotX-numX);
numX=dotX+1;
}
num=stod(subs);
if(num<0 || num>255) //如果子段数字小于0或大于255,地址或掩码错误
return false;
else{
if(i<=3)
ip[i]=num;
else
mask[i-4]=num;
}
}
if(i==7){ //取出最后一个数字段(最长为3)
subs=s.substr(numX,3); //字符串截止为止,最长3位
num=stod(subs);
if(num<0 || num>255) //如果子段数字小于0或大于255,地址或掩码错误
return false;
else
mask[3]=num;
}
//判断掩码是否合法
i=0;
while(mask[i]==255)
i++;
if(i==4)
return false; //255.255.255.255是非法掩码
int rule=254; //rule是二进制前面全为1,后面全为0的8bits数
int d=1; //每次为2的次方,使rule实现左移效果
int j;
for(j=0;j<8;j++){
if(mask[i]==rule) //第一个非255的掩码子段是前面全1,后面全0则跳出
break;
d=d*2;
rule-=d; //向左移位,减少头1,增加尾0
}
if(j==8)
return false; //掩码子段不是前面全1,后面全0,掩码不合法
while(i!=3){
i++;
if(mask[i]!=0) //非全1掩码子段后还有非0位,掩码不合法
return false;
}
if(mask[0]==0 && i==3)
return false; //0.0.0.0是非法掩码
return true;
}
int main(){
string str;
int ACount=0;
int BCount=0;
int CCount=0;
int DCount=0;
int ECount=0;
int errorCount=0;
int privateCount=0;
while(getline(cin,str)){
bool flag;
flag=Valid(str);
if(!flag){
errorCount++;
continue;
}
if(ip[0]>=1 && ip[0]<=126){
ACount++;
if(ip[0]==10)
privateCount++;
}
else if(ip[0]>=128 && ip[0]<=191){
BCount++;
if(ip[0]==172 && ip[1]>=16 && ip[1]<=31)
privateCount++;
}
else if(ip[0]>=192 && ip[0]<=223){
CCount++;
if(ip[0]==192 && ip[1]==168)
privateCount++;
}
else if(ip[0]>=224 && ip[0]<=239)
DCount++;
else if(ip[0]>=240 && ip[0]<=255)
ECount++;
}
cout<<ACount<<" "<<BCount<<" "<<CCount<<" "<<DCount<<" "<<ECount<<" "<<errorCount<<" "<<privateCount<<endl;
return 0;
}