题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
方法一:
对输入的字符串str进行扫描,如果遇到数字0~9,则继续扫描下一个;如果遇到特殊字符:+,-,小数点'.',e,E,则按照下列标准进行检测;如果遇到其他字符,则返回false;
遇到特殊字符后,按照如下规则进行判断:
1、如果是+或者-:+-号只能出现在str开头或者在字符e、E之后,所以判断if( i == 0 || str[i-1] == 'e' || str[i-1] == 'E' ),是则继续下一个,否则返回false;
2、如果是小数点'.':不符合以下规则则返回false,否则继续下一个
- 需要判断小数点不能位于str的末尾
- 在e、E的后面不能出现小数点
- 小数点不能出现两次或两次以上
- 小数点前只能是数字0~9或者+、-
- 小数点后只能是数字0~9(不确定,剑指offer书上写的小数点后可以没有数字,如233.相当于233.0,是合法的,但代码中这样写了也是过了的)
- 需要判断e、E不能位于str的的开头或者末尾
- e、E不能出现两次或两次以上
- e、E前只能是数字0~9
- e、E后只能是数字0~9或者+、-
代码
class Solution {
public:
bool isNumeric(char* str)
{
if( str == nullptr )
return false;
bool flag_e = false;
bool flag_dot = false;
for( int i=0;str[i]!='\0';i++ )
{
if( str[i] >= '0' && str[i] <= '9' ) //遇到数字0~9,则继续扫描下一个
continue;
else if( str[i] == '+' || str[i] == '-' )
{
if( i == 0 || str[i-1] == 'e' || str[i-1] == 'E' ) //+-号只能出现在str开头或者在字符e、E之后
continue;
else
return false;
}
else if( str[i] == '.' )
{
if( flag_dot ) //小数点不能出现两次或两次以上
return false;
flag_dot = true;
if( str[i+1] == '\0' ) //小数点不能位于str的末尾
return false;
if( flag_e ) //在e、E的后面不能出现小数点
return false;
if( i != 0 && !(( str[i-1] >= '0' && str[i-1] <= '9' ) || str[i-1] == '+' || str[i-1] == '-' )) //小数点前只能是数字0~9或者+、-
return false;
if( !( str[i+1] >= '0' && str[i+1] <= '9' ) ) //小数点后只能是数字0~9
return false;
}
else if( str[i] == 'e' || str[i] == 'E' )
{
if( flag_e ) //不能出现两次或两次以上
return false;
flag_e = true;
if( i == 0 || str[i+1] == '\0' ) //e、E不能位于str的的开头或者末尾
return false;
if( !( str[i-1] >= '0' && str[i-1] <= '9' ) ) //e、E前只能是数字0~9
return false;
if( !(( str[i+1] >= '0' && str[i+1] <= '9' ) || str[i+1] == '+' || str[i+1] == '-') ) //e、E后只能是数字0~9或者+、-
return false;
}
else
return false;
}
return true;
}
};
方法二:(出自剑指offer第二版)
合法的数值可以表示为A[.[B]][e|EC]或者.B[e|EC],其中A为数值的整数部分,B紧跟着小数点为数值的小数部分,而C紧跟着e、E为数值的指数部分。在小数中,可以没有数值的整数部分,所以A部分不是必须的,如果一个数没有A部分,则小数部分不能为空。
上述A和C部分都是可能以+、-开头的0~9的数位串;B部分也是0~9的数位串,但不能有+、-。
判断字符串是否符合上述模式时,从头开始扫描,A部分可有可无,如果遇到小数点'.'后,则开始扫描B部分。如果遇到e、E,则开始扫描C部分。
代码
class Solution {
public:
bool isNumeric(const char* str)
{
if(str == nullptr)
return false;
bool numeric = scanInteger(&str);
// 如果出现'.',接下来是数字的小数部分
if(*str == '.')
{
++str;
// 下面一行代码用||的原因:
// 1. 小数可以没有整数部分,例如.123等于0.123;
// 2. 小数点后面可以没有数字,例如233.等于233.0;
// 3. 当然小数点前面和后面可以有数字,例如233.666
numeric = scanUnsignedInteger(&str) || numeric;
}
// 如果出现'e'或者'E',接下来跟着的是数字的指数部分
if(*str == 'e' || *str == 'E')
{
++str;
// 下面一行代码用&&的原因:
// 1. 当e或E前面没有数字时,整个字符串不能表示数字,例如.e1、e1;
// 2. 当e或E后面没有整数时,整个字符串不能表示数字,例如12e、12e+5.4
numeric = numeric && scanInteger(&str);
}
return numeric && *str == '\0';
}
bool scanUnsignedInteger(const char** str)
{
const char* before = *str;
while(**str != '\0' && **str >= '0' && **str <= '9')
++(*str);
// 当str中存在若干0-9的数字时,返回true
return *str > before;
}
// 整数的格式可以用[+|-]B表示, 其中B为无符号整数
bool scanInteger(const char** str)
{
if(**str == '+' || **str == '-')
++(*str);
return scanUnsignedInteger(str);
}
};