題目描述:
請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串"+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之后的指數部分。其中,A部分可以沒有,比如小數.123代表0.123。如果一個數沒有整數部分,那么小數部分必須有。
具體說來,A和C(也就是整數部分和指數部分)都是可能以"+"、"-"開頭或者沒有符號的數字串,B是數字序列,但前面不能有符號。
我們可以通過順序掃描字符串來判斷是否符合上述模式,首先盡可能多的掃描數字序列(開頭可能有正負號),如果遇到小數點,那么掃描小數部分,遇到e或者E,則開始掃描指數部分。
除了順序掃描以外,判斷一個字符串是否滿足某個模式,我們很容易想到的一個辦法是使用正則表達式,以下給出這兩種方法代碼實現。
正則表達式的解法很簡潔,關於正則表達式的語法參考另外一篇博文:正則表達式
編程實現(Java):
public class Solution {
/*
思路:表示數字的字符串遵循模式:A[.[B]][e|EC]或者.B[e|EC]
A為整數部分,B為小數部分,C為指數部分
開頭可能有正負號
兩種方法:逐位判斷、正則表達式
*/
public boolean isNumeric(char[] str) {
//方法一:逐位判斷
if(str==null)
return false;
boolean sign=false,decimal=false,hasE=false; //標記符號、小數點、指數符號E是否出現過
for(int i=0;i<str.length;i++){
if(str[i]=='e'||str[i]=='E'){ //有E或者e出現
if(i==str.length-1) //E不能是最后一位,后面必須跟指數
return false;
if(hasE) return false; //E只能出現一次
hasE=true;
}else if(str[i]=='.'){
if(hasE||decimal) //指數不能有.小數點只能出現一次
return false;
decimal=true;
}else if(str[i]=='+'||str[i]=='-'){
//第一次出現,開頭或者e之后
if(!sign && i!=0 && str[i-1]!='e' && str[i-1]!='E') //不在開頭也不在e之后
return false;
//第二次出現,E之后
if(sign && str[i-1]!='E' && str[i-1]!='e')
return false;
sign=true;
}else if(str[i]>'9'||str[i]<'0') //不合法字符
return false;
}
return true;
}
//方法二:正則表達式
//+代表出現一次或多次,*代表出現0次或多次,?代表出現0次或者一次
public boolean isNumeric(char[] str) {
String string = String.valueOf(str);
return string.matches("[\\+-]?[0-9]*(\\.[0-9]*)?([eE][\\+-]?[0-9]+)?");
/*
為什么是兩個反斜杠
首先字符串中的\\被編譯器解釋為\ -------》 第一步,編譯器將字符串轉變為“正則表達式”
然后作為正則表達式,\.又被正則表達式引擎解釋為. ----------------> 第二步,才開始把第一步的結果當做是正則表達式,開始進行匹配!
如果在字符串里只寫\.的話,第一步就被直接解釋為.,之后作為正則表達式被解釋時就變成匹配任意字符了
*/
}
}