有效数判定 Valid Number

142 篇文章 20 订阅
45 篇文章 0 订阅

问题:给出一个字符串,判断它是否是一个有效的数字。

什么叫有效的数字呢?

整数 ,小数 "2.5",正数 "+25",负数"-25",科学计数法"-2e1+0"。

特殊用例:

“.5”, “5.” 认为是有效数字。

无效用例:

“.", "e25", "25e", "2e5e5", "2.5.5", "2e2.5"

输入检查:左右两端出现空格是允许的,内部不能有空格。

方法1:依据上面所能想到的无效用例,处理零碎的细节。

方法2:将零碎的细节用有限状态自动机来表示。

方法3:偷懒直接用strtod函数。


方法1:处理零碎的细节。

class Solution {
public:
    bool isNumber(const char *s) {
        if(s == NULL)
            return false;
            
        int ex, dot;
        ex = dot = 0; // only once
        
        while(*s == ' ') // space
            s++;
            
        if(*s == '+' || *s == '-') // sign
            s++;
            
        if(isNum(*s)) // first char is numeric
            s++;
        else if(*s == '.') // if first char is '.'
        {
            s++;
            dot = 1;
            if(isNum(*s)) // then second char has to be numeric
                s++;
            else
                return false;
        }
        else
            return false;
        
        while(*s != '\0')
        {
            if(*s == '.')
            {
                if(ex == 1 || dot == 1)
                    return false;
                dot = 1;
            }
            else if(*s == 'e')
            {
                if(ex == 1)
                    return false;
                ex = 1;
                if(*(s+1) == '+' || *(s+1) == '-') //sign for exponent
                    s++;
                if(!isNum(*(s+1))) // numeric after 'e' 
                    return false;
            }
            else if(*s == ' ')  // space has to be on the right side
            {
                break;
            }
            else if(!isNum(*s)) //other letter
            {
                return false;
            }
            
            s++;
        }
        while(*s == ' ') // space
            s++;
        if(*s == '\0')
            return true;
        else
            return false;
    }
    
    bool isNum(const char c)
    {
        return (c >= '0' && c <= '9'); // 0<=c<=9
    }
};

方法2:有限状态自动机。

对于这个思想,最重要的是构建状态转换矩阵。其中,每一行代表一种状态,每一列代表使状态转移的一种输入。

可能的输入有6种:无效字符0、 空格1、正负号2、数字3点4、e5。

可能的状态有8种:
-1 错误态, 任何状态接收到无效字符都会进入错误态,一旦进入错误态,状态就不会再转换下去。
0  初始态,可接受空格、正负号、数字、点。
1  接收到正负号而来,可接受数字、点。
2  由状态3接收到点而来,可接受数字、空格、e。
3  由状态0/1/3接收到数字而来,可接受数字、e、空格、点。
4  由状态2/3/9接收到数字而来,可接受数字、e、空格。
5  由状态2/3/4接收到e而来,可接受正负号、数字。
6  由状态5接收到正负号而来,可接受数字。
7  由状态5/6接收到数字而来,可接受数字、空格。
8  由状态2/3/4/7接收到空格而来,可接受空格。
9  由状态0/1接收到点而来,可接受数字。

状态0是初始状态,状态2、3、4、7、8可作为终止状态。

根据状态和输入,构造状态转换矩阵。

{
     -1, 0, 1, 3, 9, -1, //状态0:""
     -1, -1,-1, 3, 9, -1, //状态1:"+"
     -1, 8, -1, 4, -1, 5, //状态2:"2."
     -1, 8, -1, 3, 2, 5, //状态3:"2"
     -1, 8, -1, 4, -1, 5, //状态4:"2.3"
     -1, -1, 6, 7, -1, -1, //状态5:"2.3e"
     -1, -1, -1, 7, -1, -1, //状态6:"2.3e+"
     -1, 8, -1, 7, -1, -1, //状态7:"2.3e+4"
     -1, 8, -1, -1, -1, -1, //状态8:"2.3e+4 "
     -1, -1, -1, 4, -1, -1 //状态9:"."
};

#include <iostream>
#include <stdio.h>
using namespace std;

class Solution {
public:
    enum InputType
    {
        INVALID,    //0
        SPACE,      //1
        SIGN,       //2
        DIGIT,      //3
        DOT,        //4
        EXPONENT,   //5
    };
   
    bool isNumber(const char *s) {
        if(s == NULL)
            return false;
       
        const int transitionTable[][6] =
        {
            -1, 0,  1, 3, 9, -1,      //状态0:""
            -1, -1,-1, 3, 9, -1,     //状态1:"+"
            -1, 8, -1, 4, -1, 5,      //状态2:"2."
            -1, 8, -1, 3, 2, 5,       //状态3:"2"
            -1, 8, -1, 4, -1, 5,      //状态4:"2.3"
            -1, -1, 6, 7, -1, -1,     //状态5:"2.3e"
            -1, -1, -1, 7, -1, -1,    //状态6:"2.3e+"
            -1, 8,  -1, 7, -1, -1,    //状态7:"2.3e+4"
            -1, 8,  -1, -1, -1, -1,   //状态8:"2.3e+4 "
            -1, -1, -1, 4, -1, -1     //状态9:"."
        };
        int state = 0;
        InputType input;
        while(*s != 0)
        {
            if(*s == ' ')
                input = SPACE;
            else if(*s == '+' || *s == '-')
                input = SIGN;
            else if(*s == '.')
                input = DOT;
            else if(*s == 'e' || *s == 'E')
                input = EXPONENT;
            else if(*s >= '0' && *s <= '9')
                input = DIGIT;
            else
                input = INVALID;
           
            state = transitionTable[state][input];
            if(state == -1)
                return false;
            ++s;
            //cout<<state<<" ";
        }
        //cout<<endl;
        return (state == 2 || state == 3 || state == 4 || state == 7 || state == 8);
    }
};

int main()
{
    Solution s;
    char str[100];
    bool r;
    while(scanf("%s", str) != EOF)
    {
        r = s.isNumber(str);
        cout<<"result :"<<r<<endl;
    }
    return 1;
}

方法3:偷懒。

double strtod (const char* str, char** endptr);

将字符串形式的浮点数转化为double类型。 
参数一,str为输入字符串。
参数二,二重指针,函数返回后,endptr会指向str中第一个浮点数之后的位置。
返回值,转化成的double浮点数。

class Solution {
public:
    bool isNumber(const char *s) {
        char *left;
        strtod(s, &left);
        if(left == s)
            return false;
        while(*left != 0)
        {
            if(*left != ' ')
                return false;
            ++left;
        }
        return true;
    }
};

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值