【劍指offer】面試題20:表示數值的字串
阿新 • • 發佈:2019-01-06
題目:請實現一個函式用來判斷字串是否表示數值(包括整數和小數)。例如,字串 ”+100”、”5e2”、”-123”、”3.1416”和”-1E-16”都表示數值。 但是”12e”、”1a3.14”、”1.2.3”、”+-5”和”12e+4.3”都不是。
合法的數值可以表示為A[.[B]][e|EC]或者.B[e|EC]。
其中A為整數部分,B為小數部分,C為e|E的指數部分。在純小數的時候,可能沒有整數部分,如小數.123等於0.123,是合法的。所以A部分不是必須的。
A和C都是整數,可以帶符號,也可不帶。而B是一個無符號整數。
以表示數值的字串“123.45e+6”為例,“123”是它的整數部分A,“45”是它的小數部分B,“+6”是它的指數部分C。
判斷一個字串是否複合上訴模式時,首先儘可能多地掃描0~9的數位(有可能在起始處有‘+’ 或 ‘-’),也就是前面模式中表示數值的整數A部分。如果遇到小數點 ‘.’,則開始掃描表示數值小數部分的B部分。如果遇到‘e’或者‘E’,則開始掃描表示數值指數部分的C部分。
整個過程的程式碼實現如下:
public class ExpressNumByString_Demo2 { private int index = 0; public boolean isNumeric(char[] str){ if(str.length < 1){ return false; } // 整數部分 boolean flag = scanInteger(str); // 如果出現'.',則接下來是數字的小數部分 if(index < str.length && str[index] == '.'){ index++; // 下面一行程式碼用||的原因: // 1.小數可以沒有整數部分,如:.123等於0.123 // 2.小數點後面可以沒有數字,如233.等於233.0 // 3.當然,小數點前面和後面都可以有數字,如:233.666 flag = scanUnsignedInteger(str) || flag; } // 如果出現'e'或者'E',則接下來是數字的整數部分 if(index < str.length && (str[index] == 'E' || str[index] == 'e')){ index++; // 下面一行程式碼用&&的原因: // 1.當e或E前面沒有數字時,整個字串不能表示數字,如:e1、.e1 // 2.當e或E後面沒有整數時,整個字串不能表示數字,如:12e、12e+5.4 flag = flag && scanInteger(str); } return flag && index == str.length; } // 用來掃描可以表示正負‘+’或者‘-’為起始的0~9的範圍 private boolean scanInteger(char[] str) { if(index < str.length && (str[index] == '+' || str[index] == '-')){ index++; } return scanUnsignedInteger(str); } // 用來掃描字串中0~9的數位 private boolean scanUnsignedInteger(char[] str) { int start = index; while(index < str.length && str[index] >= '0' && str[index] <= '9'){ index++; } // 是否存在整數 return start < index; } public static void main(String[] args) { ExpressNumByString_Demo2 n = new ExpressNumByString_Demo2(); char[] str = {'1','0','0'}; boolean numeric = n.isNumeric(str); System.out.println(numeric); } }
-
其他解法1:
public class ExpressNumByString { public boolean isNumeric(char[] str){ if(str == null){ return false; } // 標記:符號位、小數點以及 e/E是否出現過 boolean sign = false, decimal = false, hasE = false; for(int i = 0; i < str.length; i++){ if(str[i] == 'e' || str[i] == 'E'){ // e/E 後面一定要跟數字 if(i == str.length - 1){ return false; } if(hasE){ // 不能同時存在兩個e return false; } hasE = true; }else if(str[i] == '+' || str[i] == '-'){ // 第2次出現‘+、-’符號,則必須緊接在e之後 if(sign && str[i - 1] != 'e' && str[i - 1] != 'E'){ return false; } // 第1次出現‘+、-’符號,如果不是在字串的開頭,則也必須緊接在e之後 // 開頭:i = 0,跟在e之後即str[i - 1] = e 或者 E if(!sign && i > 0 && str[i - 1] != 'e' && str[i - 1] != 'E'){ return false; } sign = true; }else if(str[i] == '.'){ // e後面不能跟小數部分,小數點不能出現兩次 // .肯定出現在e/E之前,所以在此之前hasE都應該為false if(hasE || decimal){ return false; } decimal = true; }else if(str[i] < '0' || str[i] > '9'){ // 不合法字元 return false; } } return true; } }
-
其他解法2:直接使用正則表示式【但是如果是現場面試的話一般不建議使用】
以下對正則進行解釋:
[\\+\\-]? -> 正或負符號出現與否
\\d* -> 整數部分是否出現,如-.34 或 +3.34均符合
(\\.\\d+)? -> 如果出現小數點,那麼小數點後面必須有數字;否則一起不出現
([eE][\\+\\-]?\\d+)? -> 如果存在指數部分,那麼e或E肯定出現,+或-可以不出現,緊接著必須跟著整數;或者整個部分都不出現
public class ExpressNumByString_Demo3 {
/*
以下對正則進行解釋:
[\\+\\-]? -> 正或負符號出現與否
\\d* -> 整數部分是否出現,如-.34 或 +3.34均符合
(\\.\\d+)? -> 如果出現小數點,那麼小數點後面必須有數字;
否則一起不出現
([eE][\\+\\-]?\\d+)? -> 如果存在指數部分,那麼e或E肯定出現,+或-可以不出現,
緊接著必須跟著整數;或者整個部分都不出現
*/
public boolean isNumeric(char[] str){
String string = String.valueOf(str);
String regex = "[\\+\\-]?\\d*(\\.\\d+)?([eE][\\+\\-]?\\d+)?";
return string.matches(regex);
}
}