表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。

数值(按顺序)可以分成以下几个部分:

  1. 若干空格
  2. 一个 小数 或者 整数
  3. (可选)一个 'e' 或 'E' ,后面跟着一个 整数
  4. 若干空格

小数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+' 或 '-'
  2. 下述格式之一:

    1. 至少一位数字,后面跟着一个点 '.'
    2. 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
    3. 一个点 '.' ,后面跟着至少一位数字

整数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+' 或 '-'
  2. 至少一位数字

部分数值列举如下:

  • ["+100", "5e2", "-123", "3.1416", "-1E-16", "0123"]

部分非数值列举如下:

  • ["12e", "1a3.14", "1.2.3", "+-5", "12e+5.4"]

示例 1:

输入:s = "0"
输出:true

示例 2:

输入:s = "e"
输出:false

示例 3:

输入:s = "."
输出:false

示例 4:

输入:s = "    .1  "
输出:true

提示:

  • 1 <= s.length <= 20
  • s 仅含英文字母(大写和小写),数字(0-9),加号 '+' ,减号 '-' ,空格 ' ' 或者点 '.' 。

思路:

有限状态机,枚举状态,及状态遇到字符,转换为其他状态。从左到右枚举字符串,当前字符所代表的含义就是一个状态,空格就用初始状态表示,+、-号是一个状态,字符0~9是一个状态,小数点是一个状态,小数点前后有空格的也是一个状态,小数部分是一个状态,e或者E是一个状态,指数部分是一个状态,不同的状态下遇到适合的字符,转换为下一个状态,比如初始状态遇到空格还是初始状态,初始状态遇到+、-号转换为符号状态

然后定义字符类别:加减符号、数字符号、小数点、指数符号等等。

代码:

class Solution {
public:
    enum State {
        STATE_INITIAL,//初始状态
        STATE_INT_SIGN,//整数部分的加减号
        STATE_INTEGER,//整数
        STATE_POINT,//小数点
        STATE_POINT_WITHOUT_INT,//小数点前有空格或啥没有
        STATE_FRACTION,//小数部分
        STATE_EXP,//指数符号e或者E
        STATE_EXP_SIGN,//指数部分的加减号
        STATE_EXP_NUMBER,//指数部分数字
        STATE_END//结束状态
    };
    enum CharType {
        CHAR_SPACE,//空格
        CHAR_SIGN,//加减号
        CHAR_NUMBER,//数字
        CHAR_POINT,//小数点
        CHAR_EXP,//指数符号e或者E
        CHAR_ILLEGAL//非法符号
    };
    CharType toCharType(char ch) {
        if(ch >= '0' && ch <= '9') {
            return CHAR_NUMBER;
        }
        else if(ch == 'e' || ch == 'E') {
            return CHAR_EXP;
        }
        else if(ch == '.') {
            return CHAR_POINT;
        }
        else if(ch == '+' || ch == '-') {
            return CHAR_SIGN;
        }
        else if(ch == ' ') {
            return CHAR_SPACE;
        }
        else {
            return CHAR_ILLEGAL;
        }
    }
    bool isNumber(string s) {
        unordered_map<State, unordered_map<CharType, State>> transfer{
            {
                STATE_INITIAL, {//初始状态只能接受空格、数字、小数点、加减号
                    {CHAR_SPACE, STATE_INITIAL},
                    {CHAR_NUMBER, STATE_INTEGER},
                    {CHAR_POINT, STATE_POINT_WITHOUT_INT},
                    {CHAR_SIGN, STATE_INT_SIGN}
                }
            },{
                STATE_INT_SIGN, {//整数加减符号只能接受数字、小数点
                    {CHAR_NUMBER, STATE_INTEGER},
                    {CHAR_POINT, STATE_POINT_WITHOUT_INT}
                }
            },{
                STATE_INTEGER, {//整数部分只能接受数字、指数符号、小数点、和空格
                    {CHAR_NUMBER, STATE_INTEGER},
                    {CHAR_EXP, STATE_EXP},
                    {CHAR_POINT, STATE_POINT},
                    {CHAR_SPACE, STATE_END}
                }
            },{
                STATE_POINT, {//小数点只能接受数字、指数符号、空格
                    {CHAR_NUMBER, STATE_FRACTION},
                    {CHAR_EXP, STATE_EXP},
                    {CHAR_SPACE, STATE_END}
                }
            },{
                STATE_POINT_WITHOUT_INT, {//不带整数的小数点只能接受数字
                    {CHAR_NUMBER, STATE_FRACTION}
                }
            },{
                STATE_FRACTION, {//小数部分只能接受数字、指数符号、空格
                    {CHAR_NUMBER, STATE_FRACTION},
                    {CHAR_EXP, STATE_EXP},
                    {CHAR_SPACE, STATE_END}
                }
            },{
                STATE_EXP, {//指数符号只能接受数字和加减号
                    {CHAR_NUMBER, STATE_EXP_NUMBER},
                    {CHAR_SIGN, STATE_EXP_SIGN}
                }
            },
            {
                STATE_EXP_SIGN, {//指数部分的加减号只能接受数字
                    {CHAR_NUMBER, STATE_EXP_NUMBER}
                }
            },{
                STATE_EXP_NUMBER,{//指数部分的数字只能接受数字和空格
                    {CHAR_NUMBER, STATE_EXP_NUMBER},
                    {CHAR_SPACE, STATE_END}
                }
            },{
                STATE_END, {//结束状态只能接受空格
                    {CHAR_SPACE, STATE_END}
                }
            }
        };
        int len = s.length();
        State state = STATE_INITIAL;
        for(int i = 0;i < len;i++) {
            CharType type = toCharType(s[i]);
            if(transfer[state].find(type) == transfer[state].end()) {
                //如果找不到当前状态对应的合法字符类别,则说明不是数字
                return false;
            }
            else {
                state = transfer[state][type];
            }
        }
        return state == STATE_INTEGER || state == STATE_POINT || state == STATE_FRACTION || state == STATE_EXP_NUMBER || state == STATE_END;
    }
};