如何找出包含在一个string中的值是否为double

在Java中,我试图找出包含在一个string中的值是否是双倍的?

  boolean isDouble(String str) { try { Double.parseDouble(str); return true; } catch (NumberFormatException e) { return false; } } 

Double的源代码中有一个关于这个的注释:

[…] 为了避免在无效string上调用此方法,并抛出NumberFormatException ,可使用下面的正则expression式来筛选inputstring: […]

下面的正则expression式的最终forms是相当长的:

 [\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]* 

然而,使用这种方法,你可以很容易地排除一些特殊的双打,如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); 

你可以创build一个Scanner(String)并使用hasNextDouble()方法。 从它的javadoc:

如果使用nextDouble()方法将此扫描器input中的下一个标记解释为double值,则返回true 。 扫描仪不会超过任何input。

例如,这个片段:

 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())); } 

会产生以下输出:

  foo:错误
    1:是的
  2.3:真的
   1f:错误
 0.2d:错误
 3.14:是的
 public boolean isDouble(String value) { try { Double.parseDouble(value); return true; } catch (NumberFormatException e) { return false; } } 

使用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(); } 

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

经过的时间分析:235毫秒
双打:24966
经过的时间扫描:31358毫秒
双打:24966
经过的时间正则expression式(天真):1829毫秒
双打:24966
经过的时间正则expression式(编译):109毫秒
双打:24966

正则expression式方法在正则expression式复杂的情况下运行相当快,但仍然不如使用Double.parseDouble(s)parsing那么快。 正如在评论中指出的那样,有一些像NaN这样的值通过parsing器,可能不应该。

更新:

按照@ Gabebuild议的方式预编译正则expression式会使所有不同。 编译的正则expression式现在是明确的赢家。

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

 NumberUtils.isNumber(aString); 

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

注意:为了parsing双打,如果小数点分隔符是一个点,它将起作用.

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

更好地使用:

 NumberUtils.isCreatable(aString); 

你可以尝试用Double.parseDouble(String s)parsing它

如果parsing成功,这将返回double,如果parsing不成功则返回exception。

所以你可以把所有东西都包含在一个包含try-catch的函数中,如果你有一个exception则返回false,如果你有一个实际的值,则返回true。

我会build议这样的:

 try { d = Double.parseDouble(myString); } catch (NumberFormatException ex) { // Do something smart here... } 

其他人则猜测你可能也想知道input不是用整数表示的。 根据您的要求,这可能会快速和肮脏的工作:

 public static void main(String[] args) throws Exception { System.out.println(isNonIntegerDouble("12")); //false System.out.println(isNonIntegerDouble("12.1")); //true System.out.println(isNonIntegerDouble("12.0")); //true } public static boolean isNonIntegerDouble(String in) { try { Double.parseDouble(in); } catch (NumberFormatException nfe) { return false; } try { new BigInteger(in); } catch (NumberFormatException nfe) { return true; } return false; } 

在这一点上,我觉得string匹配是一个更合适的select,但是。

您可以尝试将其与正则expression式匹配,如下所述: http : //www.regular-expressions.info/floatingpoint.html

相关问题:

正则expression式分析国际浮点数 如何使用正则expression式检测浮点数

你可以在string上使用下面的正则expression式:

 [-+]?[0-9]*\.?[0-9]* 

看看是否匹配。

我修改了Jonas的isInteger()方法来为我自己的项目提供方法isDecimal(),并且列出了下面的代码。

可能是有人可以改变添加更多的代码来区分双精度和浮点数。

它应该出来相当迅速,可能比正则expression式好,虽然我没有检查。 唯一的缺点是它在溢出情况下的行为不端等。

请注意,我参考比尔的post什么是最好的方式来检查,看看是否一个string表示一个Java中的整数?

  public boolean isDecimal(String str) { if (str == null) { return false; } int length = str.length(); if (length == 1 ) { return false; } int i = 0; if (str.charAt(0) == '-') { if (length < 3) { return false; } i = 1; } int numOfDot = 0; for (; i < length; i++) { char c = str.charAt(i); if (c == '.') numOfDot++; else if (c == '/') return false; else if (c < '.' || c > '9') { return false; } } if (numOfDot != 1 ) return false; return true; } 

如果你能find一种方法来隔离string中的数字,也许可以使用split方法。 让我们说num[1] = 25; 那么你可以做这样的事情来检查它是否加倍。

 boolean isDouble; if(num[1].contains(".")){ isDouble = true; } else{ isDouble = false; } 
 private boolean checkIsNumber(Object value) { try { boolean isNumber = NumberUtils.isNumber((String) value); if (!isNumber) { Double.parseDouble((String) value); } } catch (Exception e) { return false; } return true; 

}

尝试:

 boolean isDouble; try { Double.parseDouble("1.2"); isDouble = true; }catch(Exception e){ isDouble = false; } 

虽然通常不build议使用条件等exception。

  public boolean isDouble( String input ) { try { Double.parseDouble( input ); return true; } catch( Exception e) { return false; } }