首页 > 试题广场 >

是否是数字

[编程题]是否是数字
  • 热度指数:14250 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
判断给出的字符串是否是数字
一些例子:
"0"=>true
" 0.1 "=>true
"abc"=>false
"1 b"=>false
"3e10"=>true


/*
	 * 
	 * 发现解答很多都用了一些小技巧,比如正则,或者NumberFormatException
	 * 实际上这些解法都调用库函数,个人觉得不是出题者的真正意图
	 * 
	 * 
	 * Runtime: 3 ms.Your runtime beats 83.72 % of java submissions.
	 * 思路:这道题关键是分析所有会出现的情况。以及设置关键的flag来记录各种情况 
	 * 首先使用trim()函数去除前后空格。 
	 * 设置4个标志,分别是
	 * boolean pointSeen = false;//是否出现过小数点“.” 
	 * boolean eSeen =alse;//是否出现过指数标志“e” 
	 * boolean numberSeen = false;//是否出现过数字 
	 * booleannumberAfterE = true;//e后面是否有数字 
	 * 进行循环s.charAt(i):
	 * 1.如果属于[0,9],把numberSeen设为true 
	 * 2.如果是‘.’,必须之前没有遇到'.'和'e'
	 * 3.如果是'e',必须之前没有遇到过'e' 
	 * 4.如果是'+'或者'-',当前i必须是0,或者i-1上的字符是e 
	 * 5.其他情况返回false
	 */
	public boolean isNumber(String s) {
		s = s.trim();
		if (s == null || s.length() == 0)
			return false;
		// 记录是否出现过数字
		boolean numberSeen = false;
		// 是否出现过小数点
		boolean pointSeen = false;
		// 是否出现过指数标志e
		boolean eSeen = false;
		// e后是否出现过数字
		boolean numberAfterE = false;

		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);
			// 如果是数字
			if (c >= '0' && c <= '9') {
				numberSeen = true;
				numberAfterE = true;
				// 如果是小数点
			} else if (c == '.') {
				if (pointSeen || eSeen)
					return false;
				pointSeen = true;
				// 如果是e,必须没有出现过且出现过数字
			} else if (c == 'e') {
				if (eSeen || !numberSeen)
					return false;
				eSeen = true;
				numberAfterE = false;
				// 如果出现正负号,必须是首位,或者前一位是e
			} else if (c == '+' || c == '-') {
				if (i != 0 && s.charAt(i - 1) != 'e')
					return false;
			} else
				return false;
		}
		return numberSeen && numberAfterE;
	}

编辑于 2017-07-22 11:50:15 回复(5)
public class Solution {
    public boolean isNumber(String s) {
		try {
			char c = s.charAt(s.length() - 1);
			if(c == 'f' || c == 'F' || c == 'd' || c == 'D') return false;
			Double d = Double.valueOf(s);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}
}

发表于 2016-11-05 16:46:46 回复(7)
class Solution {
public:
    bool isNumber(const char *s) {
        string str(s);
        int k = str.find_first_not_of(' ');
        if(str[k]=='+' || str[k]=='-')
            k++;
        int p=0, num1=0;
        for(;str[k]>='0' && str[k]<='9' || str[k]=='.';k++)
            s[k] == '.'?p++:num1++;
        if(p>1 || num1<1)
            return false;
        
        if(str[k] == 'e' || str[k]=='E')
        {
            k++;
            if(str[k] == '+' || str[k]=='-')
                k++;
            int num2 = 0;
            for(;str[k]>='0' && str[k]<='9';k++)
                num2++;
            if(num2==0)
                return false;         }         for(;str[k]==' ';k++);         return str[k]=='\0';
    }
};

发表于 2017-10-07 01:11:41 回复(0)
public boolean isNumber(String s) {
        return s.matches("(\\s)*([+-])?(([0-9]*\\.)?([0-9]+)|([0-9]+)(\\.[0-9]*)?)([eE][\\+-]?[0-9]+)?(\\s)*");
    }

发表于 2017-05-06 14:37:31 回复(4)
class Solution {
public:
    bool isNumber(const char *s) {
        int n=strlen(s);
        if(s==NULL)
            return false;
        if(n==1&&s[0]==' ')//情形为“ ”
            return false;
        if(n==1&&s[0]=='.')//情形为“.”
            return false;
        if(n==1&&(s[0]=='e'||s[0]=='E'))//情形为“e”
            return false;
        bool ee=false;//是否出现过‘e’
        bool point=false;//是否出现过.
        bool nums=false;//是否出现过数字
        bool mark=false;//在e前出现的正负号
        bool mark1=false;//在e后出现的正负号
        int i=0;
        while(s[i]!='\0'){
            if(s[i]=='-'||s[i]=='+'||s[i]=='e'||s[i]=='E'||s[i]=='.'||(s[i]>='0'&&s[i]<='9')||s[i]==' '){
                if(s[i]=='-'||s[i]=='+'){
                    if(ee==true){//如果实在e后出现的正负号
                        if(mark1==false){
                            mark1=true;
                            int j=i+1;
                            if(j>=n||!(s[j]>='0'&&s[j]<='9'))//e+/e-
                                return false;
                        }
                        else
                            return false;//e后正负号多次出现
                    }
                    else{//e前出现的正负号
                        
                    	if(nums==true||point==true)//8+/.+
                        	return false;
                        else{
                            if(mark==true)//如果e前正负号出现多次
                                return false;
                            else
                            	mark=true;
                        }
                    }
                    
                }
                if(s[i]==' '){
                    if(nums==false&&ee==false&&point==false&&mark==false);
                    else{//如果在中间位置出现‘ ’
                        int j=i+1;
                        while(j<n){
                            if(s[j]!=' ')
                                return false;
                            j++;
                        }
                    }
                    
                }
                if(s[i]=='.'){
                    if(ee==false){
                        if(point==false){
                            

                            	point=true;
                        }
                        else//e前出现多个小数点
                            return false;                    
                    }
                    else//e后出现多个小数点
                        return false;
                }
                if(s[i]=='E'||s[i]=='e'){
                    if(ee==false){
                        if(i==n-1||(nums==false&&point==false)||(nums==false&&point==true))
                            return false;//e后出现小数点/e前没有任何信息
                        else
                        	ee=true;
                    }
                    else
                        return false;
                    
                    int j=i+1;
                    while(j<n){
                        if(s[j]==' ')
                            j++;
                        else
                            break;
                    }
                    if(j>=n)//e后没有数字
                        return false;
                }
                if(s[i]>='0'&&s[i]<='9')
                    nums=true;
                i++;
            }
            else
                return false;
        }
        if(nums==false&&point==true)//如果没有数字只有小数点
            return false;
        return true;
    }
};

发表于 2016-06-13 20:28:45 回复(3)
// 亲测本机上没问题,提交却显示错误,难道是因为我用的是Java8?
public class Solution {
    public boolean isNumber(String s) {
        if (s.charAt(s.length()-1) > '9' || s.charAt(s.length()-1) < '0') return false;
        try {
            Double.valueOf(s);
        } catch (Exception e) {
            return false;
        }

        return true;
    }
}

编辑于 2017-07-02 23:38:52 回复(0)
class Solution {
public:
  bool isNumber(const char *s) 
 {
   string str(s);
   int index = str.find_first_not_of(' ');
   if(str[index] == '+' || str[index] == '-')
      index++;
   int points = 0,numbers = 0;
   for(;str[index]>='0' && str[index]<='9' || str[index]=='.';index++)
      s[index] == '.' ? ++points : ++ numbers;
   if(points>1 || numbers<1)
     return false;

   if(str[index] == 'e' || str[index] == 'E')
   {
      index++;
      if(str[index] == '+' || str[index] == '-')
        index++;
      int afterE =0;
      for(;str[index]>='0' && str[index]<='9';index++)
        afterE++;
      if(afterE<1)
        return false;
   }
   for(;str[index]==' ';index++){}
   return str[index]=='\0';
  }
};

发表于 2017-07-14 11:31:08 回复(0)
C32头像 C32
 public boolean isNumber(String s) {
       
        return s.matches("(\\s)*([+-])?(([0-9]*\\.)?([0-9]+)|([0-9]+\\.))([eE][+-]?[0-9]+)?(\\s)*");
    }
编辑于 2017-05-09 11:10:29 回复(0)
public class Solution {
    public boolean isNumber(String s) {
    	try {
    		Double valueOf = Double.valueOf(s);
                //排除Double类对特殊的末尾字符为F(f)或D(d)的处理,其他如果不是数字类型,则catch!
    		if(s.indexOf("f")>-1 || s.indexOf("F")>-1 || s.indexOf("d")>-1 || s.indexOf("D")>-1){
    			return false;
    		}
    		return true;
		} catch (Exception e) {
			return false;
		}
    }
}

发表于 2016-10-08 16:37:21 回复(0)
有限状态机
class Solution {
public:
    bool isNumber(const char *s) {
        enum InputType {
            INVALID, SPACE, SIGN, DOT, E, DIGIT, LEN
        };
        int trans[][LEN] = {
            {-1,  0,  1,  2, -1,  3},
            {-1, -1, -1,  2, -1,  3},
            {-1, -1, -1, -1, -1,  4},
            {-1,  5, -1,  4,  6,  3},
            {-1,  5, -1, -1,  6,  4},
            {-1,  5, -1, -1, -1, -1},
            {-1, -1,  7, -1, -1,  8},
            {-1, -1, -1, -1, -1,  8},
            {-1,  5, -1, -1, -1,  8}
        };
        int state = 0;
        while (*s) {
            InputType input;
            if (isspace(*s)) {
                input = SPACE;
            } else if (*s == '+' || *s == '-') {
                input = SIGN;
            } else if (*s == '.') {
                input = DOT;
            } else if (*s == 'e' || *s == 'E') {
                input = E;
            } else if (isdigit(*s)) {
                input = DIGIT;
            } else {
                input = INVALID;
            }
            state = trans[state][input];
            if (state == -1) {
                return false;
            }
            s++;
        }
        return state == 3 || state == 4 || state == 5 || state == 8;
    }
};

发表于 2016-09-17 16:25:34 回复(0)
class Solution {
public:
    bool isNumber(const char *str) {
    int zhuang[9][6]={{-1,0,1,2,-1,3},
					{-1,-1,-1,2,-1,3},
					{-1,-1,-1,-1,-1,4},
					{-1,5,-1,4,6,3},
					{-1,5,-1,-1,6,4},
					{-1,5,-1,-1,-1,-1},
					{-1,-1,7,-1,-1,8},
					{-1,-1,-1,-1,-1,8},
                    {-1,5,-1,-1,-1,8}},i,zhuangtai=0,jieshou;
	for(i=0;str[i]!='\0';i++)
	{
		if(str[i]==' ')
			jieshou=1;
		else if(str[i]=='.')
			jieshou=3;
		else if('0'<=str[i]&&str[i]<='9')
			jieshou=5;
		else if(str[i]=='+'||str[i]=='-')
			jieshou=2;
		else if(str[i]=='e')
			jieshou=4;
		else 
			jieshou=0;
		zhuangtai=zhuang[zhuangtai][jieshou];
		if(zhuangtai==-1)
			return false;
	}
	if(zhuangtai==3||zhuangtai==4||zhuangtai==5||zhuangtai==8)
		return true;
	else
		return false;
    }
};

发表于 2016-08-16 12:02:05 回复(0)
为啥允许小数点开头和小数点结尾呢
发表于 2022-11-28 19:22:09 回复(0)

这道题目有点类似于atoi(将字符串转化为整数),回想一下atoi:如果第一个非空格字符不存在或者不是数字也不是正负号则返回零,否则开始做类型转换,之后检测到非数字(包括结束符 \0) 字符时停止转换,返回整型数。

这道题目里面我们采取以下步骤:

  1. 忽略前置空格和后置空格
  2. 正负号只能出现在最前面
  3. 句点只能出现一次
  4. 不能含有正负号、句点、数字以外的字符
  5. 不能为空
  6. 不能是单独的正负号或句点

如果是科学计数法,需要符合:

  1. 没有空格紧邻e
  2. e的前面是数字
  3. e的后面是整数

具体的实现方案:

  • 先判断是否包含e
  • 如果包含e,则先判断e的前后是否紧邻空格
    • 如果是的,返回false
    • 如果不是,判断e的前面是否为数字,后面是否为整数
  • 如果不包含e,直接判断是否为数字
  • 为了实现方便,定义了一个help函数,它会返回三个可能的值,0表示非数字,1表示整数,2表示小数

代码如下:

//
// Created by jt on 2020/9/26.
//
class Solution {
public:
    bool isNumber(const char *s) {
        // 判断是否含有e
        const char *p = s;
        while (*p) {
            if (*p == 'e') break;
            ++p;
        }
        if (*p) {
            // 如果含有e,先判断e的前后是否有空格
            if (p-1 >= s && *(p-1) != ' ' && *(p+1) && *(p+1) != ' ')
                return help(s, p) > 0 && help(p+1, nullptr) == 1;
            else
                return false;
        }
        return help(s, nullptr) > 0;
    }

    int help(const char *s, const char *end) {
        // 返回0表示非数字 返回1表示整数 返回2表示小数
        if (s == end) return 0;
        // 忽略前置空格
        while (*s == ' ') ++s;
        // 如果只有空格
        if (!(*s)) return 0;
        // 记录正负号和句点
        bool hasSign = false, hasDot = false, hasNum = false;
        if (*s == '+' || *s == '-') { hasSign = true; ++s; }
        while (*s && *s != ' ' && s != end) {
            if (hasSign && (*s == '+' || *s == '-')) return 0;
            if (hasDot && *s == '.') return 0;
            if (*s == '.') { hasDot = true; ++s; continue; }
            if (*s < '0' || *s > '9') return 0;
            hasNum = true;
            ++s;
        }
        // 忽略后置空格
        while (*s && s != end) {
            if (*s != ' ') return 0;
            ++s;
        }
        if (hasNum && !hasDot) return 1;
        if (hasNum && hasDot) return 2;
        return 0;
    }
};
发表于 2020-09-26 17:03:48 回复(0)
class Solution {
public:
    bool isNumber(const char *s)
	{
		int i,start=1,a[2]={0,0},loc[2]={0,0},k1=0,k2=0;
		vector<int>n;
		if(s=="")
			return false;
		for(i=0;i<strlen(s);i++)
		{
			if(s[i]!=' ')
			{
				start=i+1;
				break;
			}
		}


		if(s[start-1]=='+'||s[start-1]=='-')
		{
			start++;
			n.push_back(0);
		}
		for(i=start-1;i<strlen(s);i++)
		{
			if(s[i]<'0'||s[i]>'9')
			{
				if(s[i]=='.')
				{			
					if(i!=strlen(s)-1&&(s[i+1]>'9'||s[i+1]<'0')&&s[i+1]!=' ')
						if(s[i+1]!='e'&&s[i+1]!='E')
							return false;
						else if(k2==0)
							return false;
					
					a[0]++;
					loc[0]=i+1;
					n.push_back(0);
				}
				else if(s[i]=='e'||s[i]=='E')
				{
					if(i==strlen(s)-1)
						return false;
					else
						if(s[i+1]>'9'||s[i+1]<'0')
							if(s[i+1]!='+'&&s[i+1]!='-')
								return false;
							else
								if(i+1==strlen(s))
									return false;
								else
									if(s[i+2]>'9'||s[i+2]<'0')
										return false;
					a[1]++;
					loc[1]=i+1;
					n.push_back(0);
				}
				else if(s[i]=='+'||s[i]=='-')
					if(s[i-1]!='e'&&s[i-1]!='E')
						return false;	
					else ;
				else
					if(s[i]==' ')
						n.push_back(1);
					else return false;
				
			}
			else 
			{
				n.push_back(0);
				k2=1;
			}
		}
		if(k2==0)
			return false;
		if(a[0]>1||a[1]>1)
			return false;
		if(loc[0]>loc[1]&&loc[1]!=0)
			return false;
		if(start==loc[1])
			return false;

		for(i=0;i<n.size();i++)
		{
			if(n[i]==0)
				if(k1==0||k1==1)
					k1=1;
				else
					return false;
			else
				if(k1==1)
					k1=2;
		}
		if(k1==0)
			return false;
		return true;   
    }
};
太多陷阱了。。。。眼睛快瞎了,用最笨的办法,今天不想改进了
发表于 2020-07-04 19:22:37 回复(2)
    /*
    * 目的:判断一个字符是否是数字
    * 参考:剑指offer-20
    */
    bool scanUInt(const char**str){
        const char* before = *str;
        while(**str!='\0' && **str>='0' && **str<='9')
            ++(*str);
        return *str>before;
    }
    bool scanInt(const char**str){
        while(**str=='+' || **str=='-')
            ++(*str);
        return scanUInt(str);
    }
    bool isNumber(const char *s) {
        if (s == nullptr) 
            return false;
        while(*s==' ')
            s++;
        bool numeric = scanInt(&s);
        if (*s == '.'){
            s++;
            numeric=scanUInt(&s)||numeric;
        }
        if (*s == 'e' || *s=='E'){
            s++;
            numeric=numeric&&scanInt(&s);
        }
        while(*s==' ')
            s++;
        return numeric && *s=='\0';
    }
发表于 2019-12-09 17:19:23 回复(0)
class Solution {
public:
    bool isNumber(const char *s) {
        bool numberSeen = false;
        bool eSeen = false;
        bool numberAfterE = false;
        bool pointSeen = false;
        int start = 0;
        int end = strlen(s) - 1;
        while (start < strlen(s)) {
            if (s[start] != ' ') {
                break;
            }
            start++;
        }
        while (end >= 0) {
            if (s[end] != ' ') {
                break;
            }
            end--;
        }
        for (int i = start;i <= end;i++) {
            char c = s[i];
            if (c >= '0' && c <= '9') {
                numberSeen = true;
                numberAfterE = true;
            } else if (c == '.') {
                if (pointSeen || eSeen) {
                    return false;
                }
                pointSeen = true;
            } else if (c == 'e' || c == 'E') {
                if (eSeen || !numberSeen) {
                    return false;
                }
                eSeen = true;
                numberAfterE = false;
            } else if (c == '+' || c == '-') {
                if (i != start && (s[i - 1] != 'e' && s[i - 1] != 'E')) {
                    return false;
                }
            } else {
                return false;
            }
        }
        return numberSeen && numberAfterE;
    }
};

发表于 2019-11-14 23:37:48 回复(0)
    bool isNumber(const char *s) {
        string ss(s);
        trim(ss);
        bool numsign = 0;
        bool pointsign = 0;
        bool esign = 0;
        bool numafte = 0;
        int len = ss.size();
        for(int i=0;i<len;++i){
            if(ss[i]>='0'&&ss[i]<='9'){
                numsign = 1;
                numafte = 1;
            }else if(ss[i] == '.'){
                if(pointsign||esign)return false;
                pointsign = 1;
            }else if(ss[i]=='e'){
                if(esign||!numsign)return false;
                esign = 1;
                numafte = 0;
            }else if(ss[i]=='+'||ss[i]=='-'){
                if(i!=0&&ss[i-1]!='e')return false;
            }
             else return false;
        }
        return numsign&&numafte;
    }
    void trim(string &s){
        if(!s.empty()){
            s.erase(0,s.find_first_not_of(' '));
            s.erase(s.find_last_not_of(' ')+1);
        }
    }

发表于 2019-08-28 21:11:56 回复(1)
public class Solution {
public boolean isNumber(String s) {
        s = s.trim();
        String smallNumber = "([0-9]+\\.|\\.[0-9]|[0-9])[0-9]*";
        String pattern = "[-+]?" + smallNumber + "([eE][-+]?[0-9][0-9]*)?";
        return s.matches(pattern);
    }
}


发表于 2019-07-21 13:46:40 回复(0)
不知道会不会很麻烦
bool isNumber(const char *s) {
        // 需要考虑情况:
        // 非e的字母,是否有e,是否有小数点,
        // 是否为负数,e的指数是否为负数
        
        string str(s);
        
        // 先将首尾的空格去掉
        while (str.length() > 0 && str[0] == ' ') str = str.substr(1);
        while (str.length() > 0 && str[str.length() - 1] == ' ') str = str.substr(0, str.length() - 1);
        
        if (str.length() == 0) return false;
        
        bool hasE = false, isDecimal = false, isSign = false, isESign = false;
        
        for (int i = 0; i < str.length(); i ++) {
            char c = str[i];
            if (c == '-' || c == '+') {
                // 当前数字没有正负号,后面必须为数字或'.'
                if (!isSign && i == 0 && i < str.length() - 1 && (str[i + 1] >= '0' && str[i + 1] <= '9') || str[i + 1] == '.') isSign = true;
                // 为e或E的符号,必须在e或E的后面,且e或E的后面没有过符号,且+/-不在字符串的最后一个
                else if (hasE && i > 0 && (str[i - 1] == 'e' || str[i - 1] == 'E') && !isESign && i != str.length() - 1) isESign = true;
                else return false;
            } else if (c == '.') {
                // 没有过.,且没有过e或者E,'.'的前面或者后面需有数字
                if (!hasE && !isDecimal && ((i != 0 && str[i - 1] >= '0' && str[i - 1] <= '9') || (i + 1 <= str.length() - 1 && str[i + 1] >= '0' && str[i + 1] <= '9'))) isDecimal = true;
                else return false;
            } else if (c == 'e' || c == 'E') {
                // 没有过e或者E,前面需要是数字或者'.'
                if (!hasE && i != 0 && ((str[i - 1] >= '0' && str[i - 1] <= '9') || str[i - 1] == '.') && i != str.length() - 1) hasE = true;
                else return false;
            } else if (c < '0' || c > '9') {
                return false;
            }
            
        }
        
        return true;
    }

发表于 2019-06-13 20:29:44 回复(0)
//数字由三部分组成:整数部分,小数部分,指数部分
//注意数字里面含有空格
//数值的字符串遵循模式A[.[B]][e|EC]或者.B[e|EC]
class Solution {
private:
    int pos=0;
public:
    bool isNumber(const char *s) {
        if(s==nullptr)
            return false;
        while(s[pos]==' ')
            pos++;
        //判断整数部分
        bool numeric=scanInteger(s);
        //判断小数部分
        if(s[pos]=='.'){
            pos++;
            //小数可以没有整数部分:.123
            //小数点后面可以没有数字:123.
            //小数点前面和后面可以都有数字:123.4
            numeric=scanUnsignedInteger(s)||numeric;//注意||符号两边的顺序,必须保证scanUnsignedInteger(s)执行
        }
        //判断指数部分
        if(s[pos]=='e'||s[pos]=='E'){
            pos++;
            //当e|E前面没有数字时,整个字符串不能表示数字:.e1
            //当e|E后面没有整数时,整个字符串不能表示数字:12e、12e+5.4
            numeric=numeric&&scanInteger(s);
        }
        //忽略掉三种情况后字符串后面的空格
        while(s[pos]==' ')
            pos++;
        return numeric&&s[pos]=='\0';//保证三种情况后,字符串位于末尾
    } 
    bool scanUnsignedInteger(string s){
        int temp=pos;
        while(s[pos]>='0'&&s[pos]<='9')
            pos++;
        return pos>temp;//如果pos>temp,表示含有数字
    }
    bool scanInteger(string s){
        if(s[pos]=='+'||s[pos]=='-')
            pos++;
        return scanUnsignedInteger(s);
    }
};

发表于 2019-06-02 13:55:04 回复(0)