在解析字符串之前,如何检查它是否是一个数字?


当前回答

这是我知道的最快的方法来检查字符串是否为数字:

public static boolean isNumber(String str){
  int i=0, len=str.length();
  boolean a=false,b=false,c=false, d=false;
  if(i<len && (str.charAt(i)=='+' || str.charAt(i)=='-')) i++;
  while( i<len && isDigit(str.charAt(i)) ){ i++; a=true; }
  if(i<len && (str.charAt(i)=='.')) i++;
  while( i<len && isDigit(str.charAt(i)) ){ i++; b=true; }
  if(i<len && (str.charAt(i)=='e' || str.charAt(i)=='E') && (a || b)){ i++; c=true; }
  if(i<len && (str.charAt(i)=='+' || str.charAt(i)=='-') && c) i++;
  while( i<len && isDigit(str.charAt(i)) ){ i++; d=true;}
  return i==len && (a||b) && (!c || (c && d));
}
static boolean isDigit(char c){
  return c>='0' && c<='9';
}

其他回答

在Apache Commons Lang 3.5及以上版本中:NumberUtils。isCreatable或StringUtils.isNumeric。

使用Apache Commons Lang 3.4及以下版本:NumberUtils。isNumber或StringUtils.isNumeric。

你也可以使用StringUtils。isNumericSpace对于空字符串返回true,忽略字符串中的内部空格。另一种方法是使用NumberUtils。isParsable,根据Java检查数字是否可解析。(链接的javadocs包含每种方法的详细示例。)

// only int
public static boolean isNumber(int num) 
{
    return (num >= 48 && c <= 57); // 0 - 9
}

// is type of number including . - e E 
public static boolean isNumber(String s) 
{
    boolean isNumber = true;
    for(int i = 0; i < s.length() && isNumber; i++) 
    {
        char c = s.charAt(i);
        isNumber = isNumber & (
            (c >= '0' && c <= '9') || (c == '.') || (c == 'e') || (c == 'E') || (c == '')
        );
    }
    return isInteger;
}

// is type of number 
public static boolean isInteger(String s) 
{
    boolean isInteger = true;
    for(int i = 0; i < s.length() && isInteger; i++) 
    {
        char c = s.charAt(i);
        isInteger = isInteger & ((c >= '0' && c <= '9'));
    }
    return isInteger;
}

public static boolean isNumeric(String s) 
{
    try
    {
        Double.parseDouble(s);
        return true;
    }
    catch (Exception e) 
    {
        return false;
    }
}

正如@CraigTP在他的精彩回答中提到的,我也有类似的性能问题,使用exception来测试字符串是否是数值。因此,我最终分割字符串并使用java.lang.Character.isDigit()。

public static boolean isNumeric(String str)
{
    for (char c : str.toCharArray())
    {
        if (!Character.isDigit(c)) return false;
    }
    return true;
}

根据Javadoc, Character.isDigit(char)将正确识别非拉丁数字。在性能方面,我认为简单的N次比较(其中N是字符串中的字符数)在计算上比正则表达式匹配更有效。

更新:正如Jean-François Corbett在评论中指出的那样,上面的代码只验证正整数,这涵盖了我的大部分用例。下面是更新后的代码,它根据系统中使用的默认区域设置正确验证十进制数,假设十进制分隔符只在字符串中出现一次。

public static boolean isStringNumeric( String str )
{
    DecimalFormatSymbols currentLocaleSymbols = DecimalFormatSymbols.getInstance();
    char localeMinusSign = currentLocaleSymbols.getMinusSign();

    if ( !Character.isDigit( str.charAt( 0 ) ) && str.charAt( 0 ) != localeMinusSign ) return false;

    boolean isDecimalSeparatorFound = false;
    char localeDecimalSeparator = currentLocaleSymbols.getDecimalSeparator();

    for ( char c : str.substring( 1 ).toCharArray() )
    {
        if ( !Character.isDigit( c ) )
        {
            if ( c == localeDecimalSeparator && !isDecimalSeparatorFound )
            {
                isDecimalSeparatorFound = true;
                continue;
            }
            return false;
        }
    }
    return true;
}

如果您想使用正则表达式进行检查,则应该创建一个最终的静态Pattern对象,这样正则表达式只需要编译一次。编译正则表达式所花费的时间与执行匹配所花费的时间差不多,因此通过采取这种预防措施,您可以将方法的执行时间缩短一半。

final static Pattern NUMBER_PATTERN = Pattern.compile("[+-]?\\d*\\.?\\d+");

static boolean isNumber(String input) {
    Matcher m = NUMBER_PATTERN.matcher(input);
    return m.matches();
}

我假设一个数字是一个只有十进制数字的字符串,可能在开头有一个+或-号,最多有一个小数点(不是在结尾),没有其他字符(包括逗号、空格、其他计数系统中的数字、罗马数字、象形文字)。

这个解决方案非常简洁和快速,但是通过这样做,每百万次调用可以节省几毫秒的时间

static boolean isNumber(String s) {
    final int len = s.length();
    if (len == 0) {
        return false;
    }
    int dotCount = 0;
    for (int i = 0; i < len; i++) {
        char c = s.charAt(i);
        if (c < '0' || c > '9') {
            if (i == len - 1) {//last character must be digit
                return false;
            } else if (c == '.') {
                if (++dotCount > 1) {
                    return false;
                }
            } else if (i != 0 || c != '+' && c != '-') {//+ or - allowed at start
                return false;
            }

        }
    }
    return true;
}
private static Pattern p = Pattern.compile("^[0-9]*$");

public static boolean isNumeric(String strNum) {
    if (strNum == null) {
        return false;
    }
    return p.matcher(strNum).find();
}