如何确定字符串中包含的值是否为double

Gau*_*nga 23 java

在Java中,我试图找出字符串中包含的值是否为double?

unb*_*eli 31

    boolean isDouble(String str) {
        try {
            Double.parseDouble(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 这不完全有效.例如49d或49.d在这里返回true,在这种情况下通常不需要. (5认同)

aio*_*obe 13

源代码中Double有一个关于此的说明:

[...] 为了避免在无效字符串上调用此方法并NumberFormatException抛出,下面的正则表达式可用于筛选输入字符串: [...]

后面的正则表达式的最终形式很长:

[\x00-\x20]*[+-]?(NaN|Infinity|((((\p{Digit}+)(\.)?((\p{Digit}+)?)([eE][+-]?(\p{Digit}+))?)|(\.((\p{Digit}+))([eE][+-]?(\p{Digit}+))?)|(((0[xX](\p{XDigit}+)(\.)?)|(0[xX](\p{XDigit}+)?(\.)(\p{XDigit}+)))[pP][+-]?(\p{Digit}+)))[fFdD]?))[\x00-\x20]*
Run Code Online (Sandbox Code Playgroud)

但是,使用这种方法,您可以轻松地排除一些特殊的双打,例如InfinityNaN它们都被接受Double.parseDouble.例如这样:

String regExp = "[\\x00-\\x20]*[+-]?(((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)([eE][+-]?(\\p{Digit}+))?)|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)|(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*";
boolean matches = yourString.matches(regExp);
Run Code Online (Sandbox Code Playgroud)

  • 现在我预先编译了正则表达式,它的性能超过了`Double.parseDouble(s)`方法. (4认同)

Bil*_*ard 8

使用a Scanner将明显慢于使用Double.parseDouble(String s).

private static Random rand = new Random();
private static final String regExp = "[\\x00-\\x20]*[+-]?(((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)([eE][+-]?(\\p{Digit}+))?)|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)|(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*";
private static final Pattern pattern = Pattern.compile(regExp);

public static void main(String[] args) {

    int trials = 50000;
    String[] values = new String[trials];

    // initialize the array
    // about half the values will be parsable as double
    for( int i = 0; i < trials; ++i ) {
        double d = rand.nextDouble();
        boolean b = rand.nextBoolean();

        values[i] = (b ? "" : "abc") + d;
    }

    long start = System.currentTimeMillis();

    int parseCount = 0;
    for( int i = 0; i < trials; ++i ) {
        if( isDoubleParse(values[i]) ) {
            parseCount++;
        }
    }

    long end = System.currentTimeMillis();
    long elapsed = end - start;

    System.out.println("Elapsed time parsing: " + elapsed + " ms");
    System.out.println("Doubles: " + parseCount);

    // reset the timer for the next run
    start = System.currentTimeMillis();

    int scanCount = 0;
    for( int i = 0; i < trials; ++i ) {
        if( isDoubleScan(values[i]) ) {
            scanCount++;
        }
    }

    end = System.currentTimeMillis();
    elapsed = end - start;

    System.out.println("Elapsed time scanning: " + elapsed + " ms");
    System.out.println("Doubles: " + scanCount);


    // reset the timer for the next run
    start = System.currentTimeMillis();

    int regexCount = 0;
    for( int i = 0; i < trials; ++i ) {
        if( isDoubleRegex(values[i]) ) {
            regexCount++;
        }
    }

    end = System.currentTimeMillis();
    elapsed = end - start;

    System.out.println("Elapsed time regex (naive): " + elapsed + " ms");
    System.out.println("Doubles: " + naiveRegexCount);


    // reset the timer for the next run
    start = System.currentTimeMillis();

    int compiledRegexCount = 0;
    for( int i = 0; i < trials; ++i ) {
        if( isDoubleCompiledRegex(values[i]) ) {
            compiledRegexCount++;
        }
    }

    end = System.currentTimeMillis();
    elapsed = end - start;

    System.out.println("Elapsed time regex (compiled): " + elapsed + " ms");
    System.out.println("Doubles: " + compiledRegexCount);
}


public static boolean isDoubleParse(String s) {
    if( s == null ) return false;
    try {
        Double.parseDouble(s);
        return true;
    } catch (NumberFormatException e) {
        return false;
    }
}

public static boolean isDoubleScan(String s) {
    Scanner scanner = new Scanner(s);
    return scanner.hasNextDouble();
}

public static boolean isDoubleRegex(String s) {
    return s.matches(regExp);
}

public static boolean isDoubleCompiledRegex(String s) {
    Matcher m = pattern.matcher(s);
    return m.matches();
}
Run Code Online (Sandbox Code Playgroud)

当我运行上面的代码时,我得到以下输出:

经过时间解析:235毫秒
双打:24966
经过时间扫描:
31358 毫秒双打:24966
经过时间正则表达式(天真):1829毫秒
双打:24966
经过时间正则表达式(已编译):109毫秒
双打:24966

鉴于正则表达式的复杂性,正则表达式方法运行得相当快,但仍然没有简单解析使用那么快Double.parseDouble(s).正如评论中指出的那样,有一些值NaN可以通过解析器而不是.

更新:

按照@ Gabe的建议预编译正则表达式会有所不同.编译的正则表达式方法现在是明显的赢家.

  • 我怀疑如果你使用正则表达式执行`Pattern.compile`并将其分配给静态变量,模式匹配器不必每次都编译它,并且正则表达式版本会更快.当然它可以在引擎盖下做一些编译模式缓存,所以它可能没有什么区别. (2认同)

Pas*_*ent 7

您可以创建Scanner(String)并使用该hasNextDouble()方法.从它的javadoc:

返回true此扫描器输入中的下一个标记是否可以使用该nextDouble()方法解释为double值.扫描仪不会超过任何输入.

例如,这个片段:

List<String> values = Arrays.asList("foo", "1", "2.3", "1f", "0.2d", "3.14");
for (String source : values) {
    Scanner scanner = new Scanner(source);
    System.out.println(String.format("%4s: %s", source, scanner.hasNextDouble()));
}
Run Code Online (Sandbox Code Playgroud)

会产生以下输出:

 foo: false
   1: true
 2.3: true
  1f: false
0.2d: false
3.14: true


Hen*_*ann 6

public boolean isDouble(String value) {
    try {
        Double.parseDouble(value);
        return true;
    } catch (NumberFormatException e) {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 是否真的很难添加空检查? (5认同)

Łuk*_*z K 5

您可以使用Apache Commons Lang的util类:

NumberUtils.isNumber(aString);
Run Code Online (Sandbox Code Playgroud)

它是null安全的,不需要使用try-catch块.

注意:对于解析双精度数,如果小数点分隔符是点,则它可以工作.

编辑: isNumber已弃用,将从Lang 4.0中删除

更好用:

NumberUtils.isCreatable(aString);
Run Code Online (Sandbox Code Playgroud)


Uri*_*Uri 3

您可以尝试用以下方法解析它Double.parseDouble(String s)

如果解析成功,则返回双精度值;如果不可解析,则返回异常。

因此,您可以将整个事情包装在一个包含 try-catch 的函数中,如果出现异常则返回 false,如果获得实际值则返回 true。

  • @akf那是因为任何“int”值也是“double” (3认同)