题解 | #识别有效的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; } }