题目:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串 +100, 5e2, -123, 3.14e+1 都表示数值,而 12e, 1a3.12, 1.2.3, +-5 都不是。

首先我们要明白数值的格式为 A.B[e|E]C,其中 A, B, C 代表的是数字,有一点不同的是 A, C 中的前方可以有正负号,而 B 不能有正负号。我们变成的思路便是,首先扫描字符串,看是否匹配 A,即字符串的前方是否是数字(可包含正负号),接着如果碰到小数点,则扫描小数点后的字符是否是数字(不能包含正负号);最后匹配科学计数法,如果碰到 e|E,那么扫描后面的字符是否是数字(可包含正负号)。

代码如下:

public class IsNumberic {
// 全局变量,控制从哪里开始扫描字符串
private static int index;
public static boolean isNumberic(char[] str) {
if (str == null) {
return false;
}

// 扫描字符串开头是否是数字(可带正负号)
boolean numberic = scanInteger(str, 0);

if (index < str.length) {
// 如果有小数点
if (str[index] == '.') {
index++;
// 扫描小数点后的数字(不带正负号)
// 使用 || 是因为 A. 或者 .B都算有效的数值
numberic = scanUnsignedInteger(str, index) || numberic;
}
}

if (index < str.length) {
// 如果扫描到 e|E
if (str[index] == 'e' || str[index] == 'E') {
index++;
// 扫描 e|E 字符后面是否为数字(可带正负号)
numberic = numberic && scanInteger(str, index);
}
}

// 符合A.B[e|E]C的形式,并且字符串全部扫描完毕
return numberic && index == str.length;
}

// 判断从某个位置开始,后面是否有数字(可带正负号)
private static boolean scanInteger(char[] str, int start) {
if (start >= str.length) {
return false;
}
if (str[start] == '+' || str[start] == '-') {
return scanUnsignedInteger(str, start + 1);
}
return scanUnsignedInteger(str, start);
}

// 判断从某个位置开始,后面是否有数字(不带正负号)
private static boolean scanUnsignedInteger(char[] str, int start) {
index = start;
if (index < str.length) {
while(str[index] >= '0' && str[index] <= '9') {
index++;
if (index == str.length) {
break;
}
}
}
return index > start;
}

public static void main(String[] args) {
System.out.println(isNumberic(".123".toCharArray())); // true
System.out.println(isNumberic("123.".toCharArray())); // true
System.out.println(isNumberic("+.123".toCharArray())); // true
System.out.println(isNumberic("-.123".toCharArray())); // true
System.out.println(isNumberic(".123e-2".toCharArray())); // true
System.out.println(isNumberic("1.2.2".toCharArray())); // false
System.out.println(isNumberic("1.2e+2".toCharArray())); // true
}
}