第20题:表示数值的字符串

题目描述

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

测试用例:


    Test("Test1", "100", true);
    Test("Test2", "123.45e+6", true);
    Test("Test3", "+500", true);
    Test("Test4", "5e2", true);
    Test("Test5", "3.1416", true);
    Test("Test6", "600.", true);
    Test("Test7", "-.123", true);
    Test("Test8", "-1E-16", true);
    Test("Test9", "1.79769313486232E+308", true);

    printf("\n\n");

    Test("Test10", "12e", false);
    Test("Test11", "1a3.14", false);
    Test("Test12", "1+23", false);
    Test("Test13", "1.2.3", false);
    Test("Test14", "+-5", false);
    Test("Test15", "12e+5.4", false);
    Test("Test16", ".", false);
    Test("Test17", ".e1", false);
    Test("Test18", "e1", false);
    Test("Test19", "+.", false);
    Test("Test20", "", false);
    Test("Test21", nullptr, false);

 

思路:

1.形如A[.[B]][e|EC]或.[B][e|EC]的都来表示数值,其中AC为有符号整型,B为无符号整型

2.小数点前后,只要有一个整型即可,且小数点后的整型是无符号整型。
3.指数前后必须要都有有符号整型。
4.字符串里不能有除了0-9的其它字符。

 

第一遍

                       
// 整数的格式可以用[+|-]B表示, 其中B为无符号整数
bool scanInteger(const char** str) 
{
	//1.如果前面有[+|-]号,往后移一位
	if (**str == '+' || **str == '-')
		(*str)++;//注意这里(*str) 要打括号 ++比*优先级高。

	//2.返回无整形扫描
	return scanUnsignedInteger(str);
}

bool scanUnsignedInteger(const char** str)
{
	//1.定义before指针,指向str第一个字符
	const char* before = *str;
	//2.如果*str不为空,且是数字的话,进行下一个字符
	while (*str&&**str >= '0'&&**str <= '9')
		(*str)++;
	//3.如果有数字字符的话,就返回真,否则返回假
	return before < *str ? true : false;
}

// 数字的格式可以用A[.[B]][e|EC]或者.B[e|EC]表示,其中A和C都是
// 整数(可以有正负号,也可以没有),而B是一个无符号整数
bool isNumeric(const char* str)
{
	//1.如果为空
	if (!str)
		return false;

	//2.判断第一个字符是否是数值,A  
	bool numeric = scanInteger(&str);

	//3.如果遇到小数点 . 用||,因为小数点有三种情况,1.1/0.1/1.0
	if (*str == '.')
	{
		//3.1 str++成为左值,因为要取地址
		str++;
		//3.2 细节:不用return 更新numeric的值
		numeric= scanUnsignedInteger(&str) || numeric  ;//细节:先扫描小数位B,是否为unsigned,因为如果numeric==ture就不会扫描小数位了
	}

	//4.如果遇到指数e|E ,用&&,因为指数前后必须都要是数字, e2,1e是错的
	if (*str == 'e' || *str == 'E')
	{
		str++;
		numeric= numeric&&scanInteger(&str);
	}

	//5.返回是否为数值numeric,且已经扫描到了'\0'
	return numeric&&*str=='\0';
}

bug

1.左值:问题描述:
想给一个指向int型的指针赋值,以下为代码,就会在第三行报错“表达式必须为左值或者函数操作符”

int *P;
int a;
p=&(a+2);

改写成以下代码就不会报错了

int *P;
int a,b;
b=a+2;
p=&b;


问题分析:
分析一下为什么第一种写法就是错的, 究其原因就是取地址操作符&必须作用于一个左值,而(a+2)明显是一个表达式,不是一个合法的左值,当然要报错了。

左值与右值这两概念是从 c 中传承而来的,在 c 中,左值既能够出现在等号左边也能出现在等号右边,右值则是只能出现在等号右边。右值就是一个临时变量(没有在程序中申明),只有临时的地址空间,左值是在程序中具体定义了的,有其地址空间。换句话说,使用取地址符&对某个值取地址,左值能够得到地址,而右值不能得到地址! 

2.||的顺序

 //3.2 细节:不用return 更新numeric的值
        numeric= scanUnsignedInteger(&str) || numeric  ;//细节:先扫描小数位B,是否为unsigned,因为如果numeric==ture就不会扫描小数位了

3.函数返回值,不能直接返回numeric,还要检查是否到了字符串末尾

//5.返回是否为数值numeric,且已经扫描到了'\0'
    return numeric&&*str=='\0';

 第二遍

class Solution {
public:
    
    //形如A[.[B]][e|EC]或.[B][e|EC]的都来表示数值,其中AC为有符号整型,B为无符号整型
    //小数点前后,只要有一个整型即可,且小数点后的整型是无符号整型。
    //指数前后必须要都有有符号整型。
    //字符串里不能有除了0-9的其它字符。
    bool scanUnsignedInt(const char** str)
    {
        //1.定义before指针char*保存原来的str
        const char* before = *str;
        //2.如果**str不为结束符,**str的值在0-9,继续往下指
        while(**str!='\0'&&**str>='0'&&**str<='9')
            (*str)++;
        //3.比较*str和before的位置,判断是否存在数字,返回
        return before<*str?true:false;
    }
    bool scanInt(const char** str)
    {
        //1.如果有正负号,str往后指一个
        if(**str=='+' || **str == '-')
            (*str)++;
        //2.返回扫描无符号整数
        return scanUnsignedInt(str);
    }
    
    bool isNumeric(const char* string)
    {
        //1.判断是否为nullptr
        if(!string)
            return false;
        
        //2.定义标志numeric,表达是否为数字,首先扫描带符号的数值
        bool numeric=scanInt( &string);
        
        //3. 如果遇到小数,小数点后的B应该为无符号整形,小数点前后只要有一个数字就行,所以numeric用||重新赋值,
        //其中||的顺序是:scanUnsigned函数在前,因为numeric为真,就不会判断scanUnsigned函数的值了
        if(*string=='.')
        {
            string++;
            numeric=scanUnsignedInt(&string)||numeric;
        }
        //4.如果遇到指数,指数的前后都应该有数字,所以用&&
        if(*string=='e'||*string=='E')
        {
            string++;
            numeric=scanInt(&string)&&numeric;
        }
        //5.返回numeric,且string扫描到了结束符
        return numeric&&*string=='\0';
        
    }

};

网友的

class Solution {
public:
    bool isNumeric(char* str) {
        // 标记符号、小数点、e是否出现过
        bool sign = false, decimal = false, hasE = false;
        for (int i = 0; i < strlen(str); i++) {
            if (str[i] == 'e' || str[i] == 'E') {
                if (i == strlen(str)-1) return false; // e后面一定要接数字
                if (hasE) return false;  // 不能同时存在两个e
                hasE = true;
            } else if (str[i] == '+' || str[i] == '-') {
                // 第二次出现+-符号,则必须紧接在e之后
                if (sign && str[i-1] != 'e' && str[i-1] != 'E') return false;
                // 第一次出现+-符号,且不是在字符串开头,则也必须紧接在e之后
                if (!sign && i > 0 && str[i-1] != 'e' && str[i-1] != 'E') return false;
                sign = true;
            } else if (str[i] == '.') {
              // e后面不能接小数点,小数点不能出现两次
                if (hasE || decimal) return false;
                decimal = true;
            } else if (str[i] < '0' || str[i] > '9') // 不合法字符
                return false;
        }
        return true;
    }
};

编译原理中自动机(你是魔鬼吗?

class Solution {
public:
    bool isNumeric(char* string)
    {
        int i = 0;
        if(string[i]=='+' || string[i]=='-' || IsNum(string[i])){
            while(string[++i]!='\0' && IsNum(string[i]));
            if(string[i]=='.'){
                if(IsNum(string[++i])){
                    while(string[++i]!='\0' && IsNum(string[i]));
                    if(string[i]=='e'||string[i]=='E'){
                        i++;
                        if(string[i]=='+' || string[i]=='-' || IsNum(string[i])){
                            while(string[++i]!='\0' && IsNum(string[i]));
                            if(string[i]=='\0') return true;
                            else return false;
                        }else return false;
                    }else if(string[i]=='\0') return true;
                    else return false;
                }else if(string[++i]=='\0') return true;
                else return false;
            }else if(string[i]=='e'||string[i]=='E'){
                i++;
                if(string[i]=='+' || string[i]=='-' || IsNum(string[i])){
                    while(string[++i]!='\0' && IsNum(string[i]));
                    if(string[i]=='\0') return true;
                    else return false;
                }else return false;
            }else if(string[i]=='\0') return true;
            else return false;           
        }else return false;
    }
     
    bool IsNum(char ch)
    {
        if(ch<'0'||ch>'9') return false;
        else return true;
    }
};

正则表达式(魔鬼

//正则表达式解法
public class Solution {
    public boolean isNumeric(char[] str) {
        String string = String.valueOf(str);
        return string.matches("[\\+\\-]?\\d*(\\.\\d+)?([eE][\\+\\-]?\\d+)?");
    }
}
/*
以下对正则进行解释:
[\\+\\-]?            -> 正或负符号出现与否
\\d*                 -> 整数部分是否出现,如-.34 或 +3.34均符合
(\\.\\d+)?           -> 如果出现小数点,那么小数点后面必须有数字;
                        否则一起不出现
([eE][\\+\\-]?\\d+)? -> 如果存在指数部分,那么e或E肯定出现,+或-可以不出现,
                        紧接着必须跟着整数;或者整个部分都不出现
*/
 
 
//参见剑指offer
public class Solution {
    private int index = 0;
  
    public boolean isNumeric(char[] str) {
        if (str.length < 1)
            return false;
         
        boolean flag = scanInteger(str);
         
        if (index < str.length && str[index] == '.') {
            index++;
            flag = scanUnsignedInteger(str) || flag;
        }
         
        if (index < str.length && (str[index] == 'E' || str[index] == 'e')) {
            index++;
            flag = flag && scanInteger(str);
        }
         
        return flag && index == str.length;
         
    }
     
    private boolean scanInteger(char[] str) {
        if (index < str.length && (str[index] == '+' || str[index] == '-') )
            index++;
        return scanUnsignedInteger(str);
         
    }
     
    private boolean scanUnsignedInteger(char[] str) {
        int start = index;
        while (index < str.length && str[index] >= '0' && str[index] <= '9')
            index++;
        return start < index; //是否存在整数
    }
}

 

posted @ 2019-02-05 22:12 lightmare 阅读(...) 评论(...) 编辑 收藏