53、表达数值的字符串
题⽬描述
请实现⼀个函数⽤来判断字符串str是否表示数值(包括科学计数法的数字,⼩数和整数)。科学计数法的数字(按顺序)可以分成以下⼏个部分:
- 若⼲空格
- ⼀个整数或者⼩数
- (可选)⼀个 ' e ' 或 ' E ' ,后⾯跟着⼀个整数(可正可负)
- 若⼲空格
⼩数(按顺序)可以分成以下⼏个部分:
- 若⼲空格
- (可选)⼀个符号字符('+' 或 '-')
- 可能是以下描述格式之⼀:
- ⾄少⼀位数字,后⾯跟着⼀个点 '.'
- ⾄少⼀位数字,后⾯跟着⼀个点 '.' ,后⾯再跟着⾄少⼀位数字
- ⼀个点 '.' ,后⾯跟着⾄少⼀位数字
- 若⼲空格
整数(按顺序)可以分成以下⼏个部分:
- 若⼲空格
- (可选)⼀个符号字符(' + ' 或 ' - ')
- ⾄少⼀位数字
- 若⼲空格
例如,字符串["+100","5e2","-123","3.1416","-1E-16"] 都表示数值。
但是["12e","1a3.14","1.2.3","+-5","12e+4.3"] 都不是数值。
提示:
- 1 <= str.length <= 25
- str 仅含英⽂字⺟(⼤写和⼩写),数字(0-9),加号 '+' ,减号 '-' ,空格 ' ' 或者点 '.' 。
- 如果怀疑⽤例是不是能表示为数值的,可以使⽤python 的print(float(str)) 去查看
示例1
输⼊:"123.45e+6"
返回值:true
示例2
输⼊:"1.2.3"
返回值:false
思路及解答
暴力分析拆解
这道题咋⼀看,有点复杂, case 很多,主要是分析好判断分⽀,我们可以定义⼏个变量:
- hashNum : 是否已经有数字
- hashE :是否已经有E
- hasSign :是否已经有符号
- hasDot :是否已经有⼩数点
⾸先,初始化当前的索引index =0 ,字符串头部的空格需要跳过。
- 循环判断索引是否在有效的范围内:
- 循环判断是否是数字,是数字则更新hasNum = true ,并且索引后移,直到不是数字的时候,跳出循环。
- 跳出循环后,需要判断当前的index 是否合法,不合法直接break
- 取出当前索引的字符c :
- 如果c 是e 或者E :
- 如果前⾯已经出现过E ,或者前⾯没有数字,直接返回false
- 否则, hasE 置为true ,其他的置为false ,也就是E后⾯可以继续出现符号数字和⼩数点了
- 如果c 是“ + ”或者“ - ”:
- 前⾯如果已经出现过数字或者符号或者⼩数点,都不是合法的
- 否则hasSign 置为true ,表示符号出现过
- 如果c 是⼩数点“ . ”
- 如果前⾯已经有⼩数点或者有E出现了,那么就是⾮法的,返回false
- 否则hasDot 置为true
- 如果c 为空格,直接跳出循环
- 否则,直接返回false
- 如果c 是e 或者E :
- 最后也需要跳过空格
- 最后判断是否合法的条件是:是否到达最后⼀个字符,并且出现过数字
public boolean isNumeric(String str) {
int size = str.length();
int index= 0 ;
// 默认全部是false
boolean hashNum=false ,hasE=false ,hasSign=false ,hasDot=false;
// 跳过空格
while(index<size&&str.charAt(index)==' '){
index++;
}
while(index<size){
while(index<size&&str.charAt(index)>='0'&& str.charAt(index)<='9'){
index++;
// 表示前⾯有数字
hashNum = true;
}
-
// 到末尾直接跳出
if(index==size){
break;
}
-
char c = str.charAt(index);
if(c=='e'||c=='E'){
// 前⾯有E或者没有数字在前⾯
if(hasE||!hashNum){
return false;
}
hasE = true;
// 出现E了后⾯⼜可以出现数字了
hashNum = false;
hasSign = false;
hasDot = false;
}else if(c=='+'||c=='-'){
if(hasSign||hashNum||hasDot){
return false;
}
hasSign = true;
}else if(c=='.'){
if(hasDot||hasE){
return false;
}
hasDot =true;
}else if(c==' '){
break;
}else{
return false;
}
index++;
}
// 跳过空格
while(index<size&&str.charAt(index)==' '){
index++;
}
return hashNum &&index==size;
}这道题,其实本质是状态的切换,最最重要的⼀点,是 E 出现之后,其实⼩数点和符号,和数字,都是可以再出现的,可以理解为 E 就是⼀个分割线。
借助正则表达式
直接借助正则表达式进⾏匹配,但是并不太推荐这种解法:
public class Solution {
/**
* 代码中的类名、⽅法名、参数名已经指定,请勿修改,直接返回⽅法规定的值即可
*
*
* @param str string字符串
* @return bool布尔型
*/
public boolean isNumeric (String str) {
// write code here
// ^表示开头 $ 表示结尾 java中两个\\ 代表⼀个\
// * 零次或多次匹配前⾯的字符或⼦表达式
// ?零次或⼀次匹配前⾯的字符或⼦表达式
// + ⼀次或多次匹配前⾯的字符或⼦表达式
// [] 字符集。匹配包含的任⼀字符
// (:? )匹配 pattern 但不捕获该匹配的⼦表达式,即它是⼀个⾮捕获匹配
String p = "^[+-]?(\\d*\\.\\d+|\\d+(\\.\\d*)?)(?:[eE][+-]?\\d+)?$";
return Pattern.matches(p,str);
}
}