8

よりも優れた、よりエレガントな(および/またはおそらくより高速な)方法はありますか

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

...?


編集:私は2つの答えを選ぶことができないので、a)エレガントであり、b)「Jon Skeetが問題を解決した」と言うのはトートロジーであるため、正規表現を使用します。Jon Skeet自身がすべての問題の解決策だからです。

4

11 に答える 11

10

後で Double.valueOf (または同様のもの) を使用して実際に解析する必要があると仮定すると、より高速かつ確実に実行するために Java に組み込まれているものはないと思います。

Double.valueOf の代わりに Double.parseDouble を使用して、不必要に 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」または 16 進値をカバーしていないことに注意してください。それらを通過させるかどうかは、コンテキストによって異なります。

私の経験では、正規表現は上記のハードコーディングされたチェックよりも遅くなります。

于 2008-12-11T15:00:20.040 に答える
9

正規表現、つまり次のようなものを使用できますString.matches("^[\\d\\-\\.]+$");(負の数や浮動小数点数をテストしていない場合は、少し単純化できます)。

ただし、それがあなたが概説した方法よりも速いかどうかはわかりません。

編集:このすべての論争に照らして、私はテストを行い、これらの各メソッドの速度に関するデータを取得することにしました. 正確さはそれほどではありませんが、どれだけ速く実行されたかだけです。

私のブログで私の結果を読むことができます。(ヒント:Jon Skeet FTW)。

于 2008-12-11T14:59:56.297 に答える
8

java.text.NumberFormat(javadoc)を参照してください。

NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
Number myNumber = nf.parse(myString);
int myInt = myNumber.intValue();
double myDouble = myNumber.doubleValue();
于 2008-12-11T16:01:52.197 に答える
5

正しい正規表現は、実際には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
    }

ただし、これはローカライズされた表現を許可しません。

浮動小数点値のローカライズされた文字列表現を解釈するには、NumberFormatのサブクラスを使用します。

于 2008-12-12T16:23:56.617 に答える
3

スキート氏を活用する:

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;
    }
}
于 2008-12-11T16:05:15.963 に答える
3

StringUtils.isDouble(String)Apache Commons で使用します。

于 2008-12-11T15:04:02.187 に答える
2

いつものように、 Jakarta commons-langを使用します。しかし、それらの実装が速いかどうかはわかりません。例外に依存していません。これは、パフォーマンスの面で優れている可能性があります...

于 2008-12-11T15:01:53.300 に答える
2

これらの答えのほとんどは、ある程度受け入れられる解決策です。すべての正規表現ソリューションには、関心のあるすべてのケースで正しくないという問題があります。

String が有効な数値であることを本当に確認したい場合は、独自のソリューションを使用します。ほとんどの場合、文字列は有効な数値であり、例外が発生しないことを忘れないでください。したがって、ほとんどの場合、パフォーマンスは Double.valueOf() のパフォーマンスと同じになります。

これは、最初の本能を検証することを除いて、実際には答えではないと思います.

ランディ

于 2008-12-11T15:21:42.730 に答える
1

String の 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;
  }

}

于 2008-12-15T13:53:16.230 に答える
1

Phillの答えに従って、別の正規表現を提案できますか?

String.matches("^-?\\d+(\\.\\d+)?$");
于 2008-12-11T15:14:42.447 に答える
-1

猛烈に高速なものが必要で、どの形式を受け入れたいかが明確にわかっている場合は、ステート マシンDFAを手動で構築できます。とにかく、これは基本的に正規表現がフードの下でどのように機能するかですが、この方法で正規表現のコンパイル手順を回避でき、一般的な正規表現コンパイラよりも高速になる可能性があります。

于 2008-12-12T16:24:19.283 に答える