检测String是否为数字的最优雅方法?

是否有更好,更优雅(和/或可能更快)的方式

boolean isNumber = false; try{ Double.valueOf(myNumber); isNumber = true; } catch (NumberFormatException e) { } 

…?


编辑 :因为我不能选择两个答案我正在使用正则表达式因为a)它优雅而且b)说“Jon Skeet解决了问题”是一个重言式,因为Jon Skeet本身就是所有问题的解决方案。

我不相信Java中有任何内容可以更快,更可靠地执行它,假设稍后您将要使用Double.valueOf(或类似)实际解析它。

我使用Double.parseDouble而不是Double.valueOf来避免不必要地创建一个Double, 并且你还可以通过检查数字,e / E,和来更快地摆脱明显愚蠢的数字。 预先。 所以,像:

 public boolean isDouble(String value) { boolean seenDot = false; boolean seenExp = false; boolean justSeenExp = false; boolean seenDigit = false; for (int i=0; i < value.length(); i++) { char c = value.charAt(i); if (c >= '0' && c <= '9') { seenDigit = true; continue; } if ((c == '-' || c=='+') && (i == 0 || justSeenExp)) { continue; } if (c == '.' && !seenDot) { seenDot = true; continue; } justSeenExp = false; if ((c == 'e' || c == 'E') && !seenExp) { seenExp = true; justSeenExp = true; continue; } return false; } if (!seenDigit) { return false; } try { Double.parseDouble(value); return true; } catch (NumberFormatException e) { return false; } } 

请注意,尽管尝试了几次,但仍然不包括“NaN”或hex值。 您是否希望这些传递取决于上下文。

根据我的经验,正则表达式比上面的硬编码检查慢。

你可以使用正则表达式,比如String.matches("^[\\d\\-\\.]+$"); (如果你没有测试负数或浮点数,你可以简化一下)。

不确定这是否会比你概述的方法更快。

编辑:鉴于所有这些争议,我决定进行一项测试,并获得一些关于这些方法的速度有多快的数据。 不是那么正确,而是他们跑得多快。

您可以在我的博客上阅读我的结果。 (提示:Jon Skeet FTW)。

请参见java.text.NumberFormat (javadoc)。

 NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH); Number myNumber = nf.parse(myString); int myInt = myNumber.intValue(); double myDouble = myNumber.doubleValue(); 

正确的正则表达式实际上是在Double javadocs中给出的:

为了避免在无效字符串上调用此方法并抛出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 } 

但是,这不允许本地化表示:

要解释浮点值的本地化字符串表示forms,请使用NumberFormat的子类。

在Apache Commons中使用StringUtils.isDouble(String)

利用Skeet先生:

 private boolean IsValidDoubleChar(char c) { return "0123456789.+-eE".indexOf(c) >= 0; } public boolean isDouble(String value) { for (int i=0; i < value.length(); i++) { char c = value.charAt(i); if (IsValidDoubleChar(c)) continue; return false; } try { Double.parseDouble(value); return true; } catch (NumberFormatException e) { return false; } } 

我将一如既往地使用雅加达公共场所 ! 但我不知道他们的实施是否快速。 它不依赖于Exceptions,这可能是一个很好的thig性能……

大多数答案都是可接受的解决方案。 所有正则表达式解决方案都存在对您可能关心的所有情况都不正确的问题。

如果你真的想确保String是一个有效的数字,那么我会使用你自己的解决方案。 我想,不要忘记,大多数情况下,String将是一个有效的数字,不会引发exception。 因此,大多数情况下,性能将与Double.valueOf()的性能相同。

我想这真的不是一个答案,除了它validation了你的初始本能。

兰迪

根据Phill的回答,我可以建议另一个正则表达式吗?

 String.matches("^-?\\d+(\\.\\d+)?$"); 

我更喜欢在Strings的char []表示上使用循环并使用Character.isDigit()方法。 如果需要优雅,我认为这是最可读的

 package tias; public class Main { private static final String NUMERIC = "123456789"; private static final String NOT_NUMERIC = "1L5C"; public static void main(String[] args) { System.out.println(isStringNumeric(NUMERIC)); System.out.println(isStringNumeric(NOT_NUMERIC)); } private static boolean isStringNumeric(String aString) { if (aString == null || aString.length() == 0) { return false; } for (char c : aString.toCharArray() ) { if (!Character.isDigit(c)) { return false; } } return true; } 

}

如果你想要一些非常快速的东西,并且你非常清楚你想要接受哪种格式,你可以手工构建一个状态机DFA 。 这本质上是正则表达式的工作原理,但你可以通过这种方式避免正则表达式编译步骤,并且它可能比通用正则表达式编译器更快。