题目描述:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+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和C是带正负号的整数,且正负号位于A和C的首部,且B是不带正负号的整数
1.先看整数,按照有符号数的方法逐位比较。如果出现小数点,则说明进入小数部分,如果出现e,则说明进入指数部分
2.进入小数部分后,按照无符号数进行比较,比较完之后,要想判断是否是数值,需要和整数部分综合考量,才能判断是否是数值。会出现三种情况:(1)整数是真,小数是真,是真 (2)整数真 小数假 是真 (3)整数真,小数假 是真。 将小数判断放在前面
3.进入指数部分,按照有符号数的方式比较,要想这个字符串必须是真,必须是前面部分表示为真,e|E后面表示为真
4.不能直接返回上面整合的判断值,因为上面的情况下只判断了+,-,0~9,小数点和e这几种情况是否是数值,如果出现其他符号,index是不会++的,最后返回的时候,要判断index是否指向最后一位(因为出现a的话,index会停在a处,表示a以前的字符串不是一个数值)
public class Solution {
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.小数假,整数位真,为真,也就是整数部分后面没有小数,例如222.
//2.小数真,整数位假,为真,也就是小数部分前面没有整数,例如.123
//3.小数真,整数为真,为真,也就是小数和整数部分都有数字,例如22.2
//不能判断整数放在前面,要不然就会不去判断小数
flag=scanUnsignedInteger(str) || flag;
}
//进入指数部分
if(index < str.length && (str[index] == 'E' || str[index] == 'e')){
index++;
//下面用&&的原因:
//1.当e或E前面没有数字的时候,整个字符串不能表示数字,如.e1
//2.当e或E后面没有整数的是,整个字符串不能表示数字,例如12E
flag=flag && scanInteger(str);
}
return flag && index==str.length;
}
//判断有符号的数
private boolean scanInteger(char[] str){
if(index<str.length && (str[index]=='+' || str[index]=='-')){
index++;
}
return scanUnsignedInteger(str);
}
//判断无符号的数
private boolean scanUnsignedInteger(char[] str){
int start=index;
while(index<str.length && str[index]>='0' && str[index]<='9'){
index++;
}
//如果str中有0~9的数字,返回true
return start<index;
}
}
注意这个里面的&&和|| 的应用。刚开始报错是因为将进入小数部分的长度判断放在后面,这样的话index就是超出边界的。应该首先判断这个index是否小于字符串长度。
方法二(排除法):
(1)+,-只能放在首位或者E,e的后面
(2)E或e,以及小数点只能出现一次,并且:在有E或者e的情况下,小数点不能在E,e后面出现
(3)不能有除了数字,E,e,小数点,+,-之外的其他字符出现
(4)e或E后面必须出现数字,如果后面是+或-,continue,继续判单有没有数字,直到找到为止。
(5)不能是空符号串
public boolean isNumeric(char[] string) {
int n=string.length;
int cnt1=0,cnt2=0,pos1=0,pos2=0,cnt3=0,pos3=0;
if(n==0) return false;
for(int i=0;i<n;i++){
//这个字符串中不能出现其他字符,出现了直接返回false
if(string[i]!='e' && string[i]!='E'&&!(string[i]>='0'&&string[i]<='9')&&string[i]!='.'&&string[i]!='+'&&string[i]!='-')
return false;
//记录小数点的个数和位置
if(string[i]=='.') {
cnt1++;
pos1 = i;
}
//记录e|E出现的个数或者位数
if(string[i]=='e'||string[i]=='E') {
cnt2++;
pos2 = i;
}
//记录符号数的个数或者位数
if(string[i]=='+'||string[i]=='-') {
cnt3++;
pos3 = i;
}
}
//如果指数和小数点和符号数都出现多个
if(cnt2>=2||cnt1>=2||cnt3>=3) return false;
//如果指数出现在小数点之前
if(pos1>pos2&&cnt2!=0)return false;
//第一个字符是符号,符号的个数减1
if(string[0]=='+'||string[0]=='-')
{
cnt3--;
}
//如果指数后面的有符号,符号数减去1,很有一种情况,指数后面没有数字,所以要判断与字符串的大小
if(cnt2>0 && pos2+1<string.length && (string[pos2+1]=='+'||string[pos2+1]=='-')) {
cnt3--;
}
//如果符号数还有,说明不对
if(cnt3>0) {
return false;
}
//指数后面的
if(cnt2>0){
int flag=0;
for(int i=pos2+1;i<n;i++){
if(string[i]=='+'||string[i]=='-') continue;
if(string[i]>='0'&& string[i]<='9'){
flag=1;
break;
}
}
if(flag==0) return false;
}
return true;
}
方法三:正则表达式
import java.util.regex.Pattern;
public class Solution {
public boolean isNumeric(char[] str) {
String pattern = "^[-+]?\\d*(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?$";
String s = new String(str);
return Pattern.matches(pattern,s);
}
}