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


当前回答

基于其他答案,我写了自己的答案,它不使用模式或解析异常检查。

它检查最多一个负号和最多一个小数点。

以下是一些例子及其结果:

“1”,“-1”,“-1.5”和“-1.556”返回true

" 1 . .5”、“1。5", "1.5D", "-"和"——1"返回false

注意:如果需要,你可以修改它以接受一个Locale参数,并将其传递给DecimalFormatSymbols.getInstance()调用,以使用特定的Locale而不是当前的Locale。

 public static boolean isNumeric(final String input) {
    //Check for null or blank string
    if(input == null || input.isBlank()) return false;

    //Retrieve the minus sign and decimal separator characters from the current Locale
    final var localeMinusSign = DecimalFormatSymbols.getInstance().getMinusSign();
    final var localeDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();

    //Check if first character is a minus sign
    final var isNegative = input.charAt(0) == localeMinusSign;
    //Check if string is not just a minus sign
    if (isNegative && input.length() == 1) return false;

    var isDecimalSeparatorFound = false;

    //If the string has a minus sign ignore the first character
    final var startCharIndex = isNegative ? 1 : 0;

    //Check if each character is a number or a decimal separator
    //and make sure string only has a maximum of one decimal separator
    for (var i = startCharIndex; i < input.length(); i++) {
        if(!Character.isDigit(input.charAt(i))) {
            if(input.charAt(i) == localeDecimalSeparator && !isDecimalSeparatorFound) {
                isDecimalSeparatorFound = true;
            } else return false;
        }
    }
    return true;
}

其他回答

你可以使用NumberFormat#parse:

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}

解析它(即使用Integer#parseInt)并简单地捕获异常。=)

澄清一下:parseInt函数检查它是否可以在任何情况下解析该数字(显然),如果您想无论如何都要解析它,那么实际进行解析不会对性能造成任何影响。

如果您不想解析它(或者很少解析它),当然您可能希望采用不同的方法。

正如@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;
}

我认为唯一可靠地判断字符串是否是数字的方法是解析它。所以我只是解析它,如果它是一个数字,你可以免费得到整数形式的数字!

下面是用于检查字符串是否为数字的类。它还修复数值字符串:

特点:

删除不必要的零["12.0000000" -> "12"] 删除不必要的零["12.0580000" -> "12.058"] 删除非数字字符["12.00sdfsdf00" -> "12"] 处理负字符串值["-12,020000" -> "-12.02"] 删除多个点["-12.0.20.000" -> "-12.02"] 没有额外的库,只有标准Java

给你…

public class NumUtils {
    /**
     * Transforms a string to an integer. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToInteger(String str) {
        String s = str;
        double d;
        d = Double.parseDouble(makeToDouble(s));
        int i = (int) (d + 0.5D);
        String retStr = String.valueOf(i);
        System.out.printf(retStr + "   ");
        return retStr;
    }

    /**
     * Transforms a string to an double. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToDouble(String str) {

        Boolean dotWasFound = false;
        String orgStr = str;
        String retStr;
        int firstDotPos = 0;
        Boolean negative = false;

        //check if str is null
        if(str.length()==0){
            str="0";
        }

        //check if first sign is "-"
        if (str.charAt(0) == '-') {
            negative = true;
        }

        //check if str containg any number or else set the string to '0'
        if (!str.matches(".*\\d+.*")) {
            str = "0";
        }

        //Replace ',' with '.'  (for some european users who use the ',' as decimal separator)
        str = str.replaceAll(",", ".");
        str = str.replaceAll("[^\\d.]", "");

        //Removes the any second dots
        for (int i_char = 0; i_char < str.length(); i_char++) {
            if (str.charAt(i_char) == '.') {
                dotWasFound = true;
                firstDotPos = i_char;
                break;
            }
        }
        if (dotWasFound) {
            String befDot = str.substring(0, firstDotPos + 1);
            String aftDot = str.substring(firstDotPos + 1, str.length());
            aftDot = aftDot.replaceAll("\\.", "");
            str = befDot + aftDot;
        }

        //Removes zeros from the begining
        double uglyMethod = Double.parseDouble(str);
        str = String.valueOf(uglyMethod);

        //Removes the .0
        str = str.replaceAll("([0-9])\\.0+([^0-9]|$)", "$1$2");

        retStr = str;

        if (negative) {
            retStr = "-"+retStr;
        }

        return retStr;

    }

    static boolean isNumeric(String str) {
        try {
            double d = Double.parseDouble(str);
        } catch (NumberFormatException nfe) {
            return false;
        }
        return true;
    }

}