题目:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100"、“5e2”、”-123”、“3.1416"及”-1E-16"都表示数,但"12e"、1a3.14"、“1.2.3”、“±5"及“12e+5.4”都不是。
分析:判断一个字符串是否表示一个数值 通过题中给出的例子我们能分析出
一个字符串是否是一个能表示出一个数值的模板
+/-/ A . B E(e) +/-/ C
一个有符号整数A(整数部分)
一个符号整数B (小数部分)
E(e)后面表示 指数部分 C
C为有符号整数
我们先扫描整数部分,当然整数部分可以不存在。如.023 表示数字 0.023。(在c语言中是合法的,不信你可以用编译器试试~)
有可能会遇到+/- 。然后遇到 .,开始扫描小数部分,然后遇到 E/e开始扫描指数部分,也是会可能在开头遇到 +/- 。
综上,我们需要一个函数扫描A、C 还需要一个函数扫描B,而扫描 A 、C的函数其实就是去掉可能存在的 +/- ,然后把参数传到 扫描B的函数里。
#include<iostream>
using namespace std;
bool IsInterger(const char **str);
bool UnsignedIsInteger(const char **str);
bool IsNumber(const char *str){
if(str == NULL)
return false;
bool flag = IsInterger(&str) ; //整数部分
if(*str == '.'){
str++;
flag = UnsignedIsInteger(&str) || flag; //整数部分可以不存在 同样 小数点后面也可以没有数字 所以是 ||
}
if(*str == 'E'||*str == 'e'){
str++;
flag = flag && IsInterger(&str); //如果存在指数部分 则前面必须存在数值 而且后面也必须存在数字 且全部是数字 为整数
}
return flag && *str == '\0'; //即使走过了上面flag为true 但是那也只能证明指数部分存在的数位 前面可能存在部分整数
//比如 -12.34E12.5 所以必须要走到结尾 才是真正完成
}
bool IsInterger(const char **str){
if(**str == '+' || ** str == '-') //去掉+/-
(*str) ++;
return UnsignedIsInteger(str);
}
bool UnsignedIsInteger(const char **str){
const char *before = *str;
while(**str !='\0' && **str >= '0' && **str <= '9')
(*str)++;
return *str > before; //存在部分整数则str后移 返回true 不存在则false
}
int main()
{
const char *str1 = "+123.45+75.e-3";
const char *str2 = ".123e+12";
const char *str3 = "+123.456E+4.5";
const char *str4 = "-123.456E-5";
const char *str5 = "-.123";
const char *str6 = "-.E6";
cout<<IsNumber(str1)<<" "<<IsNumber(str2)<<" "<<IsNumber(str3)<<endl;
cout<<IsNumber(str4)<<" "<<IsNumber(str5)<<" "<<IsNumber(str6)<<endl;
return 0;
}
不知道有的朋友看完上面的代码会不会有一点疑问,我们在扫描函数的时候为什么要传const char ** , 传 一个*不就可以了吗?就是遍历指针向后走呀,我们确实是遍历指针向后走,但是我们遍历指针到指定位置,然后返回结果以后,我们希望的是再把str传到函数里的时候,是从上次遍历结束的位置开始遍历,str从上次的位置结束,只是在这个函数里到了这个位置。出了函数还是原来的指针变量,所以要传二级指针每次遍历改变指针的指向。