Java 检测字符串是否为数字的最优雅方法?

Java 检测字符串是否为数字的最优雅方法?,java,string,parsing,numbers,Java,String,Parsing,Numbers,有没有比这更好、更优雅(和/或可能更快)的方法 编辑: 因为我不能选择两个答案,所以我选择正则表达式,因为a)它很优雅,b)说“Jon Skeet解决了这个问题”是一个重言式,因为Jon Skeet自己是所有问题的解决方案。你可以使用正则表达式,例如String.matches(^[\\d\\-\\]+$”(如果不测试负数或浮点数,可以简化一点) 不过,我不确定这是否比您概述的方法更快 编辑:鉴于所有这些争议,我决定做一个测试,并获得关于每种方法的速度的一些数据。与其说是正确性,还不如说是它

有没有比这更好、更优雅(和/或可能更快)的方法


编辑
因为我不能选择两个答案,所以我选择正则表达式,因为a)它很优雅,b)说“Jon Skeet解决了这个问题”是一个重言式,因为Jon Skeet自己是所有问题的解决方案。

你可以使用正则表达式,例如
String.matches(^[\\d\\-\\]+$”(如果不测试负数或浮点数,可以简化一点)

不过,我不确定这是否比您概述的方法更快

编辑:鉴于所有这些争议,我决定做一个测试,并获得关于每种方法的速度的一些数据。与其说是正确性,还不如说是它们跑得有多快


你可以看看我的结果。(提示:Jon Skeet FTW)。

我不相信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;
    }
}
public boolean isDouble(字符串值)
{        
布尔seenDot=false;
布尔值seenExp=false;
布尔值justSeenExp=false;
布尔seenDigit=false;
对于(int i=0;i如果(c>='0'&&c我会一如既往地使用!但我不知道它是否快速。它不依赖于异常,这可能是性能方面的一个好方法…

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

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

String.matches("^-?\\d+(\\.\\d+)?$");
这些答案中的大多数都是可以接受的解决方案。所有的正则表达式解决方案都有一个问题,就是在您可能关心的所有情况下都不正确

如果您真的想确保字符串是一个有效的数字,那么我将使用您自己的解决方案。我想,不要忘记,大多数时候字符串都是一个有效的数字,不会引发异常。因此,大多数时候,性能将与Double.valueOf()相同

我想这真的不是一个答案,只是它验证了你最初的直觉

兰迪参见(javadoc)


利用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;
    }
}
专用布尔值IsValidDupleChar(字符c)
{
返回“0123456789.+-eE”.indexOf(c)>=0;
}
公共布尔值为双(字符串值)
{
对于(int i=0;i
正确的正则表达式实际上是在:

为了避免对无效字符串调用此方法并引发NumberFormatException,可以使用下面的正则表达式来筛选输入字符串:

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

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


如果你想要速度非常快的东西,并且你对想要接受的格式有一个非常清晰的概念,你可以手工构建一个状态机。这基本上就是正则表达式在后台工作的方式,但是你可以通过这种方式避免正则表达式编译步骤,它可能比一般正则表达式编译器更快。

我更喜欢使用正则表达式g在字符串的char[]表示上循环,并使用Character.isDigit()方法。如果需要优雅,我认为这是最可读的:


}

当用户输入必须是一个数字时,我就是这样做的。但是,我从来没有遇到过任何其他问题。不久前我问了一个非常类似的问题。其中一些答案可能会有帮助。Jajaja回答得很好,Epaga。对于负数和非整数,它也会失败:)有人测试过regexp是比下面Jon Skeet的方法快还是慢吗?如果你能找到一个适用于你期望的数字的方法,regexp看起来肯定更干净。有些人在遇到问题时会想“我知道,我会使用正则表达式。”现在他们有两个问题。@Paul:我以前用.NET做过测试,regex的速度要慢得多。如果你想使用regex,至少构建一次并编译它:)(我怀疑它仍然会慢一些。顺便说一句,我的代码现在比原来多了一些情况,而且它开始变得复杂了……)这个答案和john skeet的假设都是十进制分隔符。而且您也不允许使用数千个分隔符。commons-lang还检测到Java不允许的东西,例如:多个逗号、数字周围的空格等等。这取决于您想做什么。有些数字不能表示为Java双精度-它们应该是b吗是否包含e?如果您真的想知道是否最终能够转换为Java double,我怀疑如果不调用double,您将很难可靠地转换为Java double。根据我的经验,我通常需要double,并想知道它是否合法,因此我可能会更改您的方法以返回double或抛出NumberFormat异常…或者返回一个带有布尔值和双精度的小类,或者根据需要使用越界双精度。@保罗:的确如此。此时您基本上实现了.NET的“bool double.TryParse(string text,out double)”。在Java中,另一种方法是返回双精度(object)或null表示“invalid”“.Pssst…+1.0e-7是有效的双精度。Pssst…仍将失败。双精度中有两个可能的符号:尾数之前和e/e之后,符号可以是“+”。
NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
Number myNumber = nf.parse(myString);
int myInt = myNumber.intValue();
double myDouble = myNumber.doubleValue();
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;
    }
}
    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
    }
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;
  }