算法题:判断一个IP是否是合法IP

题目:如何判断一个IP是否是合法的IP,如输入:192.168.1.0,输出:合法;输入192.168.1.1222,输出:非法。

解答:先了解IP的格式,它的形式应该为:(1~255).(0~255).(0~255).(0~255)。那么可以有两种方法实现,一种是基于对字符串的处理,另一种是通过强大的正则表达式来判断。下面我将采用熟悉的Java来实现。
方法一:对字符串进行截取、分析等,代码如下:

public static void main(String[] args){
    System.out.println("请输入要验证的IP地址:");
    Scanner scanner = new Scanner(System.in);
    String ipStr = scanner.next();

    boolean isIpLegal = isIpLegal(ipStr);
    if(isIpLegal) {
        System.out.println("合法");
    }
    else{
        System.out.println("非法");
    }
}

public static boolean isIpLegal(String str){
    //1.检查ip是否为空
    if(str == null){
        return false;
    }

    //2.检查ip长度,最短为:x.x.x.x(7位),最长为:xxx.xxx.xxx.xxx(15位)
    if(str.length() < 7 || str.length() > 15){
        return false;
    }

    //3.按"."分割字符串,并判断分割出来的个数,如果不是4个,则是非法IP
    String[] arr = str.split("\\.");
    if(arr.length != 4){
        return false;
    }

    //4.对分割得到的每个字符串进行单独判断
    for(int i = 0; i < arr.length; i++){
        //对分割得到的每个字符串的每个字符进行逐一判断,如果不是数字0-9,则判定为非法IP
        for(int j = 0; j < arr[i].length(); j++){
            if (arr[i].charAt(j) < '0' || arr[i].charAt(j) > '9'){
                return false;
            }
        }
    }

    //5.对拆分的每一个字符串进行转换成数字,并判断是否在0~255
    for(int i = 0; i < arr.length; i++){
        int temp = Integer.parseInt(arr[i]);
        if(i == 0){
            if (temp < 1 || temp > 255){
                return false;
            }
        }
        else{
            if(temp < 0 || temp > 255){
                return false;
            }
        }
    }

    //6.最后,如果经过前面验证都没返回到false,返回true
    return true;
}

乍看这样的判断貌似没什么问题,但是在经过多次测试后发现,会存在三个问题。
(1)如果输入以小数点开头的非法IP,如:.x.x.x.或者.x.x.xx,编译运行后,在int temp = Integer.parseInt(arr[i])一行会有一个NumberFormatExceptin报错;
(2)如果输入以小数点结尾的非法IP,如:x.x.x.x.,最终得到的结果为“合法”;
(3)如果输入带0开头的IP,如:0x.0xx.0x.00x,最终得到的结果为“合法”;

问题(1):仔细分析是由于Java的split()方法截取时出的问题。如果输入为:.x.x.x.或者.x.x.xx的时候,split后得到的数组为arr[4]={“”,”x”, “x”, “x”}和arr[4]={“”,”x”, “x”, “xx”},就会使得后面对字符串转型时的int temp = Integer.parseInt(arr[i])那行报错NumberFormatException;
问题(2):如果输入为:x.x.x.x.,split后得到的数组为arr[4]={“x”,”x”, “x”, “x”},而不会是arr[4]={“x”,”x”, “x”, “x”, “”},根据后面的判断方法,会将此非法IP判定为合法IP。
问题(3):这是因为0xx,在Integer.parseInt()转型时会忽略掉这个0的,因此会通过判定,最后得到认为它是合法的IP。

解决方法:问题(1)(2)需要在截取字符串之前,对输入的字符串的首末字符进行判断,如果是小数点”.”,则判定为非法IP。问题(3)可以在第4步中加入判断,如果分割得到的每个字符串不是一位字符且以”0”开头,则判断为非法IP。完整代码如下:

public static void main(String[] args){
    System.out.println("请输入要验证的IP地址:");
    Scanner scanner = new Scanner(System.in);
    String ipStr = scanner.next();

    boolean isIpLegal = isIpLegal(ipStr);
    if(isIpLegal) {
        System.out.println(ipStr + " 合法");
    }
    else{
        System.out.println(ipStr + " 非法!!!");
    }
}

public static boolean isIpLegal(String str){
    //1.检查ip是否为空
    if(str == null){
        return false;
    }

    //2.检查ip长度,最短为:x.x.x.x(7位),最长为:xxx.xxx.xxx.xxx(15位)
    if(str.length() < 7 || str.length() > 15){
        return false;
    }

    //3.解决问题(1)(2): 对输入字符串的首末字符判断,如果是"."则是非法IP
    if(str.charAt(0) == '.' || str.charAt(str.length()-1) == '.'){
        return false;
    }

    //4.按"."分割字符串,并判断分割出来的个数,如果不是4个,则是非法IP
    String[] arr = str.split("\\.");
    if(arr.length != 4){
        return false;
    }

    //5.对分割出来的每个字符串进行单独判断
    for(int i = 0; i < arr.length; i++){
        //解决问题(3): 如果每个字符串不是一位字符,且以'0'开头,则是非法的IP,如:01.002.03.004
        if(arr[i].length() > 1 && arr[i].charAt(0) == '0'){
            return false;
        }
        //对每个字符串的每个字符进行逐一判断,如果不是数字0-9,则是非法的IP
        for(int j = 0; j < arr[i].length(); j++){
            if (arr[i].charAt(j) < '0' || arr[i].charAt(j) > '9'){
                return false;
            }
        }
    }

    //6.对拆分的每一个字符串进行转换成数字,并判断是否在0~255
    for(int i = 0; i < arr.length; i++){
        int temp = Integer.parseInt(arr[i]);
        if(i == 0){
            if (temp < 1 || temp > 255){
                return false;
            }
        }
        else{
            if(temp < 0 || temp > 255){
                return false;
            }
        }
    }

    //7.最后,如果经过前面验证都没返回到false,返回true
    return true;
}

方法二:采用正则表达式,代码如下:

public static void main(String[] args) {

    System.out.println("请输入要验证的IP地址:");
    Scanner scanner = new Scanner(System.in);
    String ipStr = scanner.next();
    isIpLegal(ipStr);
}

public static boolean isIpLegal(String ipStr) {
    //ip地址范围:(1~255).(0~255).(0~255).(0~255)
    String ipRegEx = "^([1-9]|([1-9][0-9])|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))(\\.([0-9]|([1-9][0-9])|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))){3}$";
    //String ipRegEx = "^([1-9]|([1-9]\\d)|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))(\\.(\\d|([1-9]\\d)|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))){3}$";
    //String ipRegEx = "^(([1-9]\\d?)|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))(\\.(0|([1-9]\\d?)|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))){3}$";
    Pattern pattern = Pattern.compile(ipRegEx);
    Matcher matcher = pattern.matcher(ipStr);
    if (matcher.matches()) {
        return true;
    } else {
        return false;
    }
}

从上面两种方法来看,不得不感叹正则表达式的强大。通过正则直接匹配来判断,代码简洁许多。

为了方便测试,我们在main函数中写入一个数组,而不再进行一个个输入,测试代码如下:
方法1测试代码:

public static void main(String[] args){
    String[] ipArr = new String[]{"abc", "123456789012345678", ".1.2.3", "1.2.3.4.", "1.2.3", "1.2.3.4.5", "1.02.003.014", "1a.2.3.4", "1.2a.3.4", "1.2.3a.4", "1.2.3.4a",
            "0.1.2.3", "-1.1.2.3", "1.-1.2.3", "1.2.-1.3", "1.2.3.-1", "256.1.2.3", "1.256.2.3", "1.2.256.3", "1.2.3.256", "1234.123.123.123", "123.1234.123.123",
            "123.123.1234.123", "123.123.123.1234", "123.123.123.123", "0.0.0.0", "1.0.0.0", "255.255.255.255", "11.22.33.44", ""};
    for (int i = 0; i < ipArr.length; i++) {
        boolean isIpLegal = isIpLegal(ipArr[i]);
        if(isIpLegal) {
            System.out.println(ipArr[i] + " 合法");
        } else {
            System.out.println(ipArr[i] + " 非法!!!");
        }
    }
}

方法2测试代码:

public static void main(String[] args) {

    String[] ipArr = new String[]{"abc", "123456789012345678", ".1.2.3", "1.2.3.4.", "1.2.3", "1.2.3.4.5", "1.02.003.014", "1a.2.3.4", "1.2a.3.4", "1.2.3a.4", "1.2.3.4a",
            "0.1.2.3", "-1.1.2.3", "1.-1.2.3", "1.2.-1.3", "1.2.3.-1", "256.1.2.3", "1.256.2.3", "1.2.256.3", "1.2.3.256", "1234.123.123.123", "123.1234.123.123",
            "123.123.1234.123", "123.123.123.1234", "123.123.123.123", "0.0.0.0", "1.0.0.0", "255.255.255.255", "11.22.33.44", ""};
    for (int i = 0; i < ipArr.length; i++) {
        boolean isIpLegal = isIpLegal(ipArr[i]);
        if (isIpLegal) {
            System.out.println(ipArr[i] + " 合法");
        } else {
            System.out.println(ipArr[i] + " 非法!!!");
        }
    }
}

测试结果:

abc 非法!!!
123456789012345678 非法!!!
.1.2.3 非法!!!
1.2.3.4. 非法!!!
1.2.3 非法!!!
1.2.3.4.5 非法!!!
1.02.003.014 非法!!!
1a.2.3.4 非法!!!
1.2a.3.4 非法!!!
1.2.3a.4 非法!!!
1.2.3.4a 非法!!!
0.1.2.3 非法!!!
-1.1.2.3 非法!!!
1.-1.2.3 非法!!!
1.2.-1.3 非法!!!
1.2.3.-1 非法!!!
256.1.2.3 非法!!!
1.256.2.3 非法!!!
1.2.256.3 非法!!!
1.2.3.256 非法!!!
1234.123.123.123 非法!!!
123.1234.123.123 非法!!!
123.123.1234.123 非法!!!
123.123.123.1234 非法!!!
123.123.123.123 合法
0.0.0.0 非法!!!
1.0.0.0 合法
255.255.255.255 合法
11.22.33.44 合法
 非法!!!

猜你喜欢

转载自blog.csdn.net/u014259820/article/details/78833196