《剑指offer》JZ53表示数值的字符串

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

 

解析:(这道题有点迷啊,其实可以直接用正则表达式匹配一下)

链接:https://www.nowcoder.com/questionTerminal/6f8c901d091949a5837e24bb82a731f2?answerType=1&f=discussion
来源:牛客网

面试的时候可以用的一种解法。也是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; //是否存在整数
 }
}

**************************************************************************************************************************************

import java.util.regex.Pattern;

public class Solution {
    public static boolean isNumeric(char[] str) {
        String pattern = "^[-+]?\\d*(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?$";
        String s = new String(str);
        return Pattern.matches(pattern,s);
    }
}

^ 和 美元符号框定正则表达式,它指引这个正则表达式对文本中的所有字符都进行匹配。如果省略这些标识,那么只要一个字符串中包含一个数字这个正则表达式就会进行匹配。如果仅包含 ^ ,它将匹配以一个数字开头的字符串。如果仅包含$ ,则匹配以一个数字结尾的字符串。

[-+]?

正负号后面的 ? 后缀表示这个负号是可选的,表示有0到1个负号或者正号

\\d*

\d的含义和[0-9]一样。它匹配一个数字。后缀 * 指引它可匹配零个或者多个数字。

(?:\\.\\d*)?

(?: …)?表示一个可选的非捕获型分组。* 指引这个分组会匹配后面跟随的0个或者多个数字的小数点。

(?:[eE][+\\-]?\d+)?

这是另外一个可选的非捕获型分组。它会匹配一个e(或E)、一个可选的正负号以及一个或多个数字。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

localhost1212

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值