题解 | #识别有效的IP地址和掩码并进行分类统计#
识别有效的IP地址和掩码并进行分类统计
https://www.nowcoder.com/practice/de538edd6f7e4bc3a5689723a7435682
import java.util.Scanner;
import java.util.regex.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// // 注意 hasNext 和 hasNextLine 的区别
// while (in.hasNextInt()) { // 注意 while 处理多个 case
// int a = in.nextInt();
// int b = in.nextInt();
// System.out.println(a + b);
// }
//计算 A,B,C,D,E 错误ip地址/掩码, 私有ip的个数
//每行 ip~掩码
//思路:三个函数,isNonIp()(0.*.*.* 和127.*.*.*哪一类都不属于); isValidIp, isValidMark, 判断ABCDE,私网 就仅通过第一段的范围判断即可
int aCnt = 0;
int bCnt = 0;
int cCnt = 0;
int dCnt = 0;
int eCnt = 0;
int errCnt =0;
int privateCnt =0;
while(in.hasNext()){
String str = in.nextLine();
String[] strs = str.split("~");
String ip = strs[0];
String mark = strs[1];
if(isNonIp(ip) || isNonIp(mark)){
continue;
}
//错误IP地址或错误掩码的计数
if(!isValidIp(ip) || !isValidMark(mark)){
errCnt ++;
continue;
}
String label = IpLable(ip);
switch(label){
case "A" :
aCnt ++;
break;
case "B":
bCnt ++;
break;
case "C":
cCnt ++;
break;
case "D":
dCnt ++;
break;
case "E":
eCnt ++;
break;
}
if(isPrivate(ip)){
privateCnt ++;
}
}
System.out.printf("%d %d %d %d %d %d %d%n", aCnt,bCnt,cCnt,dCnt,eCnt,errCnt, privateCnt);
}
/**
类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略
这个方法最先调用,否则非法ip会被统计
*/
public static boolean isNonIp(String ipStr){
String[] subIps = ipStr.split("\\.");
if(subIps.length == 4){
Integer first = Integer.parseInt(subIps[0]);
return first== 0 || first==127;
}
return false;
}
/**
判断是否为有效ip:
IP的格式,它的形式应该为:(1~255).(0~255).(0~255).(0~255)
*/
public static boolean isValidIp(String ipStr){
Pattern pattern = Pattern.compile("[^0-9\\.]");
if(pattern.matcher(ipStr).find()){ //如果能找到有非数字,非.的字符直接返回
return false;
}
String[] strs = ipStr.split("\\."); //注意转义
if(strs.length != 4){
return false;
}
for(int i =0; i< strs.length; i++){
if(strs[i] == null || strs[i].length()==0){
return false;
}
Integer sub = Integer.parseInt(strs[i]);
if(i==0 && (sub == 0 || sub == 127)){
return false;
}
if(sub>=0 && sub<=255){
continue;
}else{
return false;
}
}
return true;
}
/**
判断合法ip后,再判断ip的首段打上ABCDE的标签
*/
public static String IpLable(String ipStr){
String[] subIpStrs = ipStr.split("\\.");
Integer first = Integer.parseInt(subIpStrs[0]);
if(first >=1 && first<=126){
return "A";
}else if(first>=128 && first<=191){
return "B";
}else if(first>=192 && first<=223){
return "C";
}else if(first>=224 && first<=239){
return "D";
}else if(first>=240 && first<=255){
return "E";
}else {
return null;
}
}
/**
判断完有效ip后,判断是否为私人ip,私人ip和ABCDE不冲突,一个ip可以既是也是
*/
public static boolean isPrivate(String ipStr){
String[] subIpStrs = ipStr.split("\\.");
Integer first = Integer.parseInt(subIpStrs[0]);
Integer second= Integer.parseInt(subIpStrs[1]);
if(first==10){
return true;
}else if(first == 172 && second>=16 && second<=31){
return true;
}else if(first ==192 && second == 168){
return true;
}else {
return false;
}
}
/**
合法子网掩码为二进制下前面是连续的1,然后全是0。(例如:255.255.255.32就是一个非法的掩码)
(注意二进制下全是1或者全是0均为非法子网掩码)
*/
public static boolean isValidMark(String ipStr){
Pattern pattern = Pattern.compile("[^0-9\\.]");
if(pattern.matcher(ipStr).find()){ //如果能找到有非数字,非.的字符直接返回
return false;
}
String[] strs = ipStr.split("\\."); //注意转义
if(strs.length != 4){
return false;
}
//把四段分别转为二进制str,每一段不够八位前面补零,然后合并起来判断是否含01 即可
StringBuffer sBuf = new StringBuffer();
for(String subIpStr: strs){
Integer subIp = Integer.parseInt(subIpStr);
String binStr = Integer.toBinaryString(subIp);
int delta = 8 - binStr.length();
if(delta>0){ // 不够八位,高位补零
binStr = String.format("%"+delta+"s","").replace(" ","0") + binStr;
}
sBuf.append(binStr);
}
String totalBinStr = sBuf.toString();
if(totalBinStr.contains("01")){
return false;
}else if(!totalBinStr.contains("1")){
return false;
}else if(!totalBinStr.contains("0")){
return false;
}
return true;
}
}