扫描法
数字格式可以使用 A[.[B]][E|eC]表示A和C都是整数(可以有符号),而B是无符号整数
class Solution {
/**
* 由于java基本数据类型只能值传递,所以自定义一个引用类型
* 该类型保存了需要判别的字符串和一个该字符串的指针
*/
class IdxString {
private String s;
private Integer i;
public IdxString(String s, Integer i){
this.s = s;
this.i = i;
}
//指针i++
public void increaseI(){
this.i++;
}
public String getS(){
return this.s;
}
public Integer getI(){
return this.i;
}
//返回当前指针i处s的字符
public char charAtI(){
return this.s.charAt(this.i);
}
}
public boolean isNumber(String s) {
if(s == null)
return false;
s = s.trim();//有"1 ", " 0"的情况直接trim掉
if(s.length() == 0) return false;//考虑 s 类似" ",只有空格的情况
int len = s.length();
IdxString str = new IdxString(s, 0);
//先扫描小数点之前是否为数字
boolean isNumeric = sanInteger(str, len);
//扫描小数点之后是否为数字
if(str.getI() < len && str.charAtI() == '.'){
str.increaseI();//跳过小数点
//使用 || 的原因:
//1、会出现 .123的情况
//2、会出现 123.的情况
isNumeric = scanUnsignedInteger(str,len) || isNumeric;
}
//扫描e or E 之后是否为数字
if(str.getI() < len && (str.charAtI() == 'e' || str.charAtI() == 'E')){
str.increaseI();
//下面使用 && 是因为:
// 1、 e|E 前没有数字时不表示数字如 .e1、e1;
// 2、 e|E 后没有整数时不能表示数字如 12e、12e+5.4
isNumeric = isNumeric && sanInteger(str, len);
}
return isNumeric && str.getI() == len;//只有指针到最底,才代表扫描完毕
}
private boolean sanInteger(IdxString str, int len) {
String s = str.getS();
Integer i = str.getI();
if( i < len && (s.charAt(i) == '+' || s.charAt(i) == '-'))
str.increaseI();
return scanUnsignedInteger(str, len);
}
private boolean scanUnsignedInteger(IdxString str, int len) {
int before = str.getI();
while(str.getI() < len && str.charAtI() >='0' && str.charAtI() <= '9'){
str.increaseI();
}
return str.getI() > before;
}
}
状态机
class Solution {
public boolean isNumber(String s) {
Map[] status = {
new HashMap<>() {{put(" ", 0); put("sign", 1); put("digit", 2); put(".", 4);}}, // 0. 空格
new HashMap<>() {{put("digit", 2); put(".", 4);}}, // 1. 符号
new HashMap<>() {{put("digit", 2); put(".", 3); put("e", 5); put(" ", 8);}}, // 2. 小数点前的数字
new HashMap<>() {{put("digit", 3); put("e", 5); put(" ", 8);}}, // 3. 小数点以及小数点之后的数字
new HashMap<>() {{put("digit", 3);}}, // 4. 小数点左侧无数字时,小数点及数字
new HashMap<>() {{put("sign", 6); put("digit", 7);}}, // 5. 幂符号 e / E
new HashMap<>() {{put("digit", 7);}}, // 6. 幂符号之后的正负号
new HashMap<>() {{put("digit", 7); put(" ", 8);}}, // 7. 幂符号之后的数字
new HashMap<>() {{put(" ", 8);}}, // 8. 空格
};
int curState = 0;
String type;
for (char c : s.toCharArray()) {
if (Character.isDigit(c)) type = "digit";
else if (c == '+' || c == '-') type = "sign";
else if (c == 'e' || c == 'E') type = "e";
else if (c == ' ') type = " ";
else if (c == '.') type = ".";
else type = "?";
if (!status[curState].containsKey(type)) return false;
curState = (int)status[curState].get(type);
}
return curState == 2 || curState == 3 || curState == 7 || curState == 8;
}
}