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


  方法不止2种,简单介绍一些我看懂了的方法。

解法1:

  工作时碰到可以使用的处理方式。

public class Solution {
    public boolean isNumeric(char[] str) {
        String s = new String(str);
        try{
            double d = Double.parseDouble(s);
        }catch (Exception e) {
            return false;
        }
        return true;
    }
}
//还可以使用正则表达式的处理,写法不唯一,可以看其他题解。

解法2:

  面试的时候可以用的一种解法。也是Offer书上的思路。
  将字符串分成3个部分,A部分是整数部分,B小数点后的小数部分,c是紧跟这e的指数部分的数值。A不是必须的(如.124表示0.124,其中整数部分没有)。并且注意到,A和C是带正负号的整数,并且正负号位于A和C的首位,而B是不带正负号的整数。
  因此方法scanUnsignedInteger用来扫描字符串中0到9的数字,用来匹配B即无符号数。方法scanInteger可以扫描带正负号的数字。用来匹配A和C即有符号数。无符号数的方法是判断当前给定字符串是否由一串0到9的数字组成。
扫描的思路:

  1. 首先看整数,按照有符号数的方法逐位比较,如果出现了小数点,则说明进入到了小数部分,如果出现e,则进入指数比较。(注意,这个字符串的形式有ABC,AB,AC,B,BC,因此进入小数部分的判断后,还需要判断是否有指数部分)

  2. 进入小数部分后,按照无符号数的方式比较,比较完后,要想判断是否是数值,需要和整数部分综合考量,才能判断是否是数值。这里使用的是或操作。3种情况,1.小数假,整数真。如233.0应该是真。2.小数真,整数真,也应该是真。3.小数真,整数假,应该为真。注意,由于短路求值原理,所以必须让小数判断的方法在前,因为如果flag在前,当flag为真时,就不进行小数部分的判断了。然后在看看有没有指数部分。这里的flag标记的是整数部分的情况

  3. 进入指数部分后(可以从方式1过来也可以从方式2过来),按照有符号数的方式比较,比较完后,同样要和前面判断的部分综合考量,这里就比较粗暴了,要想整个字符串必须是数值,必须是flag表示的部分是真,指数部分也是真,即e前面要有数,后面也要有数,因此直接用&&操作比较。这里的flag标记的不是整数了,而是e前面的所有数的情况。

  4. 这样我们就拿到了当前某个字符串是否能转换成整数,但是注意到,在返回时,不能直接返回flag,,准确来说,flag标记的时在只出现0到9,小数点和e这几种情况时,是否是数值。出现其他数值时,index是不会++的,因此在最终返回时,我们要判断,index是否指向了最后一位。(如果出现了a,那么index会停在a处,而flag则表明a以前的字符串是不是一个数值)

    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++;
             // 下面一行代码用||的原因:
             // 1. 小数可以没有整数部分,例如.123等于0.123;
             // 2. 小数点后面可以没有数字,例如233.等于233.0;
             // 3. 当然小数点前面和后面可以有数字,例如233.666
             flag = scanUnsignedInteger(str) || flag;
         }
           // 如果出现'e'或者'E',接下来跟着的是数字的指数部分
         if (index < str.length && (str[index] == 'E' || str[index] == 'e')) {
             index++;
             // 下面一行代码用&&的原因:(且顺序不能颠倒,短路求值)
             // 1. 当e或E前面没有数字时,整个字符串不能表示数字,例如.e1、e1;
             // 2. 当e或E后面没有整数时,整个字符串不能表示数字,例如12e、12e+5.4
             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++;
         // 当str中存在若干0-9的数字时,返回true
         return start < index; //是否存在整数
     }
    }