如何找出包含在一个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]*
然而,使用这种方法,你可以很容易地排除一些特殊的双打,如Infinity
和NaN
都被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; } }