我知道有一百万种方法可以做到这一点,但最快的是什么?这应该包括科学记数法。
注意:我对将值转换为Double不感兴趣,我只想知道它是否可行。即private boolean isDouble(String value)
。
答案 0 :(得分:6)
您可以使用Double类使用的相同正则表达式进行检查。这里有很好的记录:
http://docs.oracle.com/javase/6/docs/api/java/lang/Double.html#valueOf%28java.lang.String%29
以下是代码部分:
为避免在无效字符串上调用此方法并抛出NumberFormatException,可以使用下面的正则表达式来筛选输入字符串:
final String Digits = "(\\p{Digit}+)";
final String HexDigits = "(\\p{XDigit}+)";
// an exponent is 'e' or 'E' followed by an optionally
// signed decimal integer.
final String Exp = "[eE][+-]?"+Digits;
final String fpRegex =
("[\\x00-\\x20]*"+ // Optional leading "whitespace"
"[+-]?(" + // Optional sign character
"NaN|" + // "NaN" string
"Infinity|" + // "Infinity" string
// A decimal floating-point string representing a finite positive
// number without a leading sign has at most five basic pieces:
// Digits . Digits ExponentPart FloatTypeSuffix
//
// Since this method allows integer-only strings as input
// in addition to strings of floating-point literals, the
// two sub-patterns below are simplifications of the grammar
// productions from the Java Language Specification, 2nd
// edition, section 3.10.2.
// Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
"((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
// . Digits ExponentPart_opt FloatTypeSuffix_opt
"(\\.("+Digits+")("+Exp+")?)|"+
// Hexadecimal strings
"((" +
// 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
"(0[xX]" + HexDigits + "(\\.)?)|" +
// 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
"(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
")[pP][+-]?" + Digits + "))" +
"[fFdD]?))" +
"[\\x00-\\x20]*");// Optional trailing "whitespace"
if (Pattern.matches(fpRegex, myString))
Double.valueOf(myString); // Will not throw NumberFormatException
else {
// Perform suitable alternative action
}
答案 1 :(得分:5)
NumberUtils#isNumber
中有一个方便的Apache Commons Lang。这有点牵强:
有效数字包括标有0x限定符的十六进制,科学记数法和用类型限定符标记的数字(例如123L)。
但我想它可能比正则表达式更快或者抛出并捕获异常。
答案 2 :(得分:2)
Apache Commons NumberUtil实际上非常快。我猜它比任何一个都快 regexp实现。
答案 3 :(得分:2)
我使用以下代码检查字符串是否可以解析为double:
public static boolean isDouble(String str) {
if (str == null) {
return false;
}
int length = str.length();
if (length == 0) {
return false;
}
int i = 0;
if (str.charAt(0) == '-') {
if (length == 1) {
return false;
}
++i;
}
int integerPartSize = 0;
int exponentPartSize = -1;
while (i < length) {
char c = str.charAt(i);
if (c < '0' || c > '9') {
if (c == '.' && integerPartSize > 0 && exponentPartSize == -1) {
exponentPartSize = 0;
} else {
return false;
}
} else if (exponentPartSize > -1) {
++exponentPartSize;
} else {
++integerPartSize;
}
++i;
}
if ((str.charAt(0) == '0' && i > 1 && exponentPartSize < 1)
|| exponentPartSize == 0 || (str.charAt(length - 1) == '.')) {
return false;
}
return true;
}
我知道输出与Double类中的正则表达式不完全相同,但这种方法更快,结果足以满足我的需要。这些是我对该方法的单元测试。
@Test
public void shouldReturnTrueIfStringIsDouble() {
assertThat(Utils.isDouble("0.0")).isTrue();
assertThat(Utils.isDouble("0.1")).isTrue();
assertThat(Utils.isDouble("-0.0")).isTrue();
assertThat(Utils.isDouble("-0.1")).isTrue();
assertThat(Utils.isDouble("1.0067890")).isTrue();
assertThat(Utils.isDouble("0")).isTrue();
assertThat(Utils.isDouble("1")).isTrue();
}
@Test
public void shouldReturnFalseIfStringIsNotDouble() {
assertThat(Utils.isDouble(".01")).isFalse();
assertThat(Utils.isDouble("0.1f")).isFalse();
assertThat(Utils.isDouble("a")).isFalse();
assertThat(Utils.isDouble("-")).isFalse();
assertThat(Utils.isDouble("-1.")).isFalse();
assertThat(Utils.isDouble("-.1")).isFalse();
assertThat(Utils.isDouble("123.")).isFalse();
assertThat(Utils.isDouble("1.2.3")).isFalse();
assertThat(Utils.isDouble("1,3")).isFalse();
}
答案 4 :(得分:0)
我认为尝试将其转换为double并捕获异常将是检查的最快方式...我能想到的另一种方式是将字符串拆分为句点('。')然后检查split数组的每个部分只包含整数......但我认为第一种方式会更快
答案 5 :(得分:0)
我尝试了以下代码块,似乎更快地抛出异常
String a = "123f15512551";
System.out.println(System.currentTimeMillis());
a.matches("^\\d+\\.\\d+$");
System.out.println(System.currentTimeMillis());
try{
Double.valueOf(a);
}catch(Exception e){
System.out.println(System.currentTimeMillis());
}
输出:
1324316024735
1324316024737
1324316024737
答案 6 :(得分:0)
异常不应该用于流控制,尽管Java的作者很难不以这种方式使用NumberFormatException
。
班级java.util.Scanner
有一个方法hasNextDouble
来检查String
是否可以被视为双倍。
引擎盖Scanner
使用正则表达式(通过预编译模式)来确定String
是否可以转换为整数或浮点数。模式以buildFloatAndDecimalPattern
方法编译,您可以在GrepCode here查看。
预编译模式的另一个好处是比使用try / catch块更快。
以下是上面引用的方法,如果GrepCode有一天消失:
private void buildFloatAndDecimalPattern() {
// \\p{javaDigit} may not be perfect, see above
String digit = "([0-9]|(\\p{javaDigit}))";
String exponent = "([eE][+-]?"+digit+"+)?";
String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
groupSeparator+digit+digit+digit+")+)";
// Once again digit++ is used for performance, as above
String numeral = "(("+digit+"++)|"+groupedNumeral+")";
String decimalNumeral = "("+numeral+"|"+numeral +
decimalSeparator + digit + "*+|"+ decimalSeparator +
digit + "++)";
String nonNumber = "(NaN|"+nanString+"|Infinity|"+
infinityString+")";
String positiveFloat = "(" + positivePrefix + decimalNumeral +
positiveSuffix + exponent + ")";
String negativeFloat = "(" + negativePrefix + decimalNumeral +
negativeSuffix + exponent + ")";
String decimal = "(([-+]?" + decimalNumeral + exponent + ")|"+
positiveFloat + "|" + negativeFloat + ")";
String hexFloat =
"[-+]?0[xX][0-9a-fA-F]*\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?";
String positiveNonNumber = "(" + positivePrefix + nonNumber +
positiveSuffix + ")";
String negativeNonNumber = "(" + negativePrefix + nonNumber +
negativeSuffix + ")";
String signedNonNumber = "(([-+]?"+nonNumber+")|" +
positiveNonNumber + "|" +
negativeNonNumber + ")";
floatPattern = Pattern.compile(decimal + "|" + hexFloat + "|" +
signedNonNumber);
decimalPattern = Pattern.compile(decimal);
}