在Java中,我正尝试确定字符串中包含的值是否为double类型?
boolean isDouble(String str) {
try {
Double.parseDouble(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
在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]*
然而,使用此方法,您可以轻松排除一些特殊的双精度浮点数,例如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);
Double.parseDouble(s)
解决方案稍微慢一些。我想在解析之前在防卫块中检查特殊的双精度值可能是最好的方法。 - Bill the LizardDouble.parseDouble(s)
方法。 - Bill the Lizard使用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
正则表达式(朴素)所需时间:1829毫秒
双精度数:24966
正则表达式(编译)所需时间:109毫秒
双精度数:24966
Double.parseDouble(s)
解析快。正如评论中指出的那样,有一些像 NaN
这样的值可以通过解析器而不应该通过。
Pattern.compile
对正则表达式进行编译,并将其赋值给一个静态变量,那么模式匹配器在每次匹配时就不必重新编译它,这样正则表达式的版本就会更快。当然,它也可能在幕后执行一些已编译模式缓存的操作,因此可能不会有任何差别。 - GabeSystem.nanoTime
将提供更精细的计时。 - Tom Hawtin - tacklineScanner(String)
对象,并使用hasNextDouble()
方法。根据其javadoc所述,如果这个扫描器的下一个标记可以使用nextDouble()
方法解释为double值,则返回true
。扫描器不会超过任何输入。例如,以下代码片段: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: 真
Double.parseDouble(s)
慢得多(数量级之差,否则我不会提到它)。也许您可以查看下面的代码并建议加速的方法。我知道每次创建新的Scanner都不好。 - Bill the Lizardpublic boolean isDouble(String value) {
try {
Double.parseDouble(value);
return true;
} catch (NumberFormatException e) {
return false;
}
}
您可以使用Apache Commons Lang中的util类:
NumberUtils.isNumber(aString);
它是空值安全的,不需要使用try-catch块。
注意:对于解析双精度浮点数,如果小数分隔符是点.
,则可以正常工作。
编辑:isNumber已被弃用并将在Lang 4.0中被移除
最好使用:
NumberUtils.isCreatable(aString);
try {
d = Double.parseDouble(myString);
}
catch (NumberFormatException ex) {
// Do something smart here...
}
您可以尝试使用Double.parseDouble(String s)
解析它。
如果解析成功,它将返回double值;如果无法解析,则会抛出异常。
因此,您可以将整个过程包装在一个try-catch函数中,在获取实际值时返回true,在遇到异常时返回false。
public static boolean isNumeric(String strNum) {
try {
Double.parseDouble(strNum);
} catch (NumberFormatException | NullPointerException nfe) {
return false;
}
return true;
}
其他人猜测您可能还想知道输入不是表示为整数。根据您的要求,这可能会快速且简单地完成工作:
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;
}
目前我觉得字符串匹配会是一个更合适的选择。
100
,它既可以是双精度浮点数也可以是长整型。 - corsiKaDouble.parseDouble
方法可以将其转换为double类型。 - aioobe