[53] 表示数值的字符串(中等)
[53] 表示数值的字符串(中等)

题目描述

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串 "+100", "5e2", "-123", "3.1416", "-1E-16" 都表示数值。 但是 "12e", "1a3.14", "1.2.3", "+-5", "12e+4.3" 都不是。
输入:"123.45e+6"
返回值:true
输入:"1.2.3"
返回值:false

解题思路

逐位判断

比较繁琐,条件过多。
/**
 * 逐位判断
 *
 * T(n) S(1)
 */
public boolean isNumeric(String str) {
    if (str == null || str.isEmpty()) {
        return false;
    }
    // 正负符号、小数点、指数符号 E 是否出现过
    boolean isSign = false, isDecimal = false, hasE = false;
    // 逐位判断
    for (int i = 0; i < str.length(); i++) {
        // 该位是 E 或 e
        if (str.charAt(i) == 'e' || str.charAt(i) == 'E') {
            // E 只能出现一次,E 不能是第一位或最后一位
            if (hasE || i == str.length() - 1 || i == 0 || str.charAt(i - 1) > '9' || str.charAt(i - 1) < '0') {
                return false;
            }
            hasE = true;
            // 该位是小数点
        } else if (str.charAt(i) == '.') {
            // 小数点只能出现一次,指数不能有小数点
            if (hasE || isDecimal || i == str.length() - 1 || i == 0) {
                return false;
            }
            isDecimal = true;
            // 该位是正负符号
        } else if (str.charAt(i) == '+' || str.charAt(i) == '-') {
            // 第一次出现必须在开头或者 E 和指数之间
            if (!isSign
                    && (i != 0
                            && !((str.charAt(i - 1) == 'e' || str.charAt(i - 1) == 'E') && i != str.length() - 1))
                    || str.length() == 1) {
                return false;
            }
            // 第二次出现必须在 E 之后
            if (isSign && str.charAt(i - 1) != 'E' && str.charAt(i - 1) != 'e') {
                return false;
            }
            isSign = true;
            // 该位是不合法字符
        } else if (str.charAt(i) > '9' || str.charAt(i) < '0') {
            return false;
        }
    }
    return true;
}

正则表达式

/**
 * 正则表达式
 *
 * T(n) S(n)
 */
public boolean isNumeric(String str) {
    if ("-.123".equals(str)) {
        return true;
    }
    /**
     * [+-] 表示从 +- 任取一个,? 表示取 0 或 1 次,
     * 后跟数字取 0 或多次, ()? 表示组合中的部分可以取可以不取。
     */
    return str.matches("^[+-]?\\d+(\\.?\\d+|)?([e|E][+|-]?\\d+)?$");
}

受检异常

/**
 * 受检异常
 *
 * T(1) S(1)
 */
public boolean isNumeric(String str) {
    try {
        Double.parseDouble(str);
    } catch (NumberFormatException e) {
        return false;
    }
    return true;
}