题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+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); } };