一个有限状态机判断字符串是否数字的例子

这几天看到有朋友在讨论这样的问题,如何快速匹给定的字符串是一个有效的科学记数法表示的数字。

如“ -1.2e-3  ”就是一个有效的数字(注意其中的空格)。

一个符合科学记数法的字符串可以包含如下字符:符号(+、-)、数字(1~9)、小数点(.)、指数(e)、以及空格。

常规方法使用分支结构进行逻辑判断的问题在于其判断的逻辑树过于复杂。而且如果需要加入新的规则,成堆的if——else无法顺利的更新与维护。

此时可考虑使用状态机来解决该问题。

为了简化,下面不考虑指数e和小数点的情况,以整数(只有符号、空格、数字位)为例,该状态机不难画出:



注意该状态机的如下状态:

[0]开始状态:只能接受空格、符号、数字;

[1]符号状态:只能接受符号;

[2]数字状态:只能接受空格、数字、结束;

[3]空格状态:只能接受空格、结束;

注意2个空格的区别。左边的空格表示第一个字符开始为空格,右边的表示中间或者后面出现的空格。二者状态不同。

这样的状态机实际上是一个有向图。可以使用矩阵来实现状态机。如下图,每行表示一个状态,每列表示一个输入条件。T表示字符串为数字;F表示不是数字。


例如,“ -1 “(首字母、末字母为空格)在该状态机中的判断路径为:0B-->0C-->1D-->2B-->3F-->T,如上图红色线条所示。

知道状态机的原理与实现,现在就可以回到开头的问题来完整解决判断字符串是否科学记数法表示的问题了。

科学记数法相比整数而言,多了不少状态。比如:

小数点(出现于数字前)的状态。如已经输入了".",此时后面必须接数字,不能接收其他输入。

小数点(出现于数字后)的状态。如已经输入了"5.",此时后面可以不接数字,表示省略0。

数字(出现于小数点前)的状态。如已经输入了"5",此时后面可以接小数点。

数字(出现于小数点后)的状态。如已经输入了".5",此时后面可以不可接小数点。

数字(出现于e前)的状态。如已经输入了"5",此时后面可以接e。

数字(出现于e后)的状态。如已经输入了"e5",此时后面不可接e。

......

状态机并不唯一,主要取决于你如何将所有状态都囊括进去。

状态机很复杂,这里就不画了,最终代码如下,状态机的实现请看代码:

enum enum_Status
    {
        Blank   = 0,
        Signal  = 1,
        Dot     = 2,
        Epsinal = 3,
        Number  = 4,
        Alphabet= 5,
        End     = 6,

        T       = 98,
        F       = 99
    };
    enum_Status GetStatus(char c)
    {
        if (c >= '0' && c <= '9')
        {
            return Number;
        }
        else if (c == ' ')
        {
            return Blank;
        }
        else if (c == '+' || c == '-')
        {
            return Signal;
        }
        else if (c == '.')
        {
            return Dot;
        }
        else if (c == 'e')
        {
            return Epsinal;
        }
        else if (c == '\0')
        {
            return End;
        }
        else
        {
            return Alphabet;
        }
    }

    bool isNumber(const char *s) 
    {    
        int statusTable[10][7] = {
           //   +  .  e  0  a  end
            {0, 1, 2, F, 8, F, F},// 0: Begin
            {F, F, 2, F, 8, F, F},// 1: Signal
            {F, F, F, F, 9, F, F},// 2: Dot [before number]
            {7, F, 4, 5, 3, F, T},// 3: number[before e]
            {7, F, F, 5, 9, F, T},// 4: Dot [after number]
            {F, 1, F, F, 6, F, F},// 5: e
            {7, F, F, F, 6, F, T},// 6: number[after e]
            {7, F, F, F, F, F, T},// 7: Blank
            {7, F, 4, 5, 8, F, T},// 8: number[before dot]
            {7, F, F, 5, 9, F, T},// 9: number[after dot]
        };
        const char *p = s;
        int status = statusTable[0][GetStatus(*p)];

        while (status != (int)T && status != (int)F)
        {
            ++p;
            status = statusTable[status][GetStatus(*p)];
        }
        return (status == T);
    } 




评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值