Javaで文字列が数値かどうかを確認する方法


887

文字列を解析する前に、文字列が数値であるかどうかをどのように確認しますか?


36
通常の式で提案されたすべてのソリューションは、16進数では機能しません。
オスカーカスティブランコ

また、matches(...)関数でnull文字列を渡すと、NullPointer例外がスローされます。
Hitesh Sahu

サードパーティのライブラリを使用しない簡潔なJava 8ソリューションについては、Max Malyshの回答を参照してください。
アンディトーマス

@HiteshSahu null文字列は最新バージョン(Java 6.xおよび7.xを含む)で正常に処理されるようです
ライフバランス

使用Integer.parseInt()が提案されているすべてのソリューションは、を使用した携帯電話番号の解析に失敗しNumberFormatExceptionます。
バグではない

回答:


691

Apache Commonsのラング 3.5以上:NumberUtils.isCreatableまたはStringUtils.isNumeric

Apache Commonsのラング 3.4以下:NumberUtils.isNumberまたはStringUtils.isNumeric

空の文字列の場合はStringUtils.isNumericSpacewhichを使用trueして、文字列の内部スペースを無視することもできます。もう1つの方法は、NumberUtils.isParsable基本的にはJavaに従って解析可能かどうかをチェックする方法です。(リンクされたjavadocには、各メソッドの詳細な例が含まれています。)


59
StringUtils.isNumeric()文字列が数字のシーケンスであるかどうかをチェックするだけなので、おそらくここでは適切ではありません。ほとんどのint型の罰金ではなく、そうなど小数、グループ区切り、との数字のためになる
ジェフ・メルカド

42
1か所に3行の関数が必要なため、ライブラリ全体を含めないため、ホイールを再発明します。
dalvarezmartinez1 2014

12
この機能のためにライブラリ全体を追加することは本当に価値がありますか?他の素晴らしいものと一緒に使用する場合は当然ですが、人々が1行のコードでこれを解決したことを考えると、おそらくやり過ぎです。
水の

7
ネガでは機能しません。そして、すべての数字の半分は負なので、.....
Paul Draper

6
@PaulDraper:あなたは正しい、StringUtils主要な標識をサポートしていませんがNumberUtils.isCreatable、チェックする必要があります、それはネガを適切にサポートしています。
palacsint 2017

904

これは通常、単純なユーザー定義関数(つまり、独自の "isNumeric"関数をロールする)で行われます。

何かのようなもの:

public static boolean isNumeric(String str) { 
  try {  
    Double.parseDouble(str);  
    return true;
  } catch(NumberFormatException e){  
    return false;  
  }  
}

ただし、この関数を頻繁に呼び出しており、数値ではないために多くのチェックが失敗することが予想される場合、失敗ごとにスローされる例外に依存しているため、このメカニズムのパフォーマンスは大きくありません。これはかなり高価な操作です。

別の方法として、正規表現を使用して数値であることの妥当性をチェックする方法があります。

public static boolean isNumeric(String str) {
  return str.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.
}

ただし、上記のRegExメカニズムには注意してください。アラビア語以外の数字(つまり、0から9以外の数字)を使用すると失敗するためです。これは、RegExの「\ d」の部分が一致するのは[0-9]のみであり、事実上、国際的に数値認識されていないためです。(これを指摘してくれたOregonGhostに感謝!)

または、Javaの組み込みjava.text.NumberFormatオブジェクトを使用して、文字列を解析した後、パーサーの位置が文字列の末尾にあるかどうかを確認することもできます。そうであれば、文字列全体が数値であると想定できます。

public static boolean isNumeric(String str) {
  NumberFormat formatter = NumberFormat.getInstance();
  ParsePosition pos = new ParsePosition(0);
  formatter.parse(str, pos);
  return str.length() == pos.getIndex();
}

7
Java Regexの\ dはラテン数字のみに一致しますか?それは.NETの正規表現のようなものだ場合は、ここで説明したように、あなたは、他の(例えばアラビア)数字で問題に遭遇します:blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
OregonGhost

3
numberFormatterソリューションは、おそらくNumberFormatExceptionソリューションをキャッチするよりもわずかに優れています。最良の方法は正規表現を使用することだと思います。
Chii、

11
.正規表現のは、小数点記号だけでなく任意の文字と一致することに注意してください。
jqno 2009

9
トライ/キャッチの費用を実現するための+1。これは実際には長期的に繰り返し使用するための恐ろしいアプローチですが、実際にはJavaでそれを行っています。
デーモンゴレム2011

5
「ラテン数字」のようなものはなく、数字0〜9は実際にはアラビア数字であることに注意してください。人々は、フォームI、II、III、IV、V、VIなどで、ラテン語を話す人々によって使用されたローマ数字、とおそらく慣れているen.wikipedia.org/wiki/Arabic_numeralsen.wikipedia.org/wiki/Roman_numerals
ダンティストン2016年

152

あなたがアンドロイドを使っているなら、あなたは使うべきです:

android.text.TextUtils.isDigitsOnly(CharSequence str)

ドキュメントはここにあります

シンプルにしてください。ほとんどの人が「再プログラム」できます(同じことです)。


4
@ kape123 :)「123.456」に数字が含まれていないことを確認してください。
Ahmed Alejo 2014年

8
注:これにより、ヌル入力に対してNPEが発生します。また、負の数や小数では機能しません。
gMale、

2
私はそれが好きです!!これは絶対に数字だと思います。ていないため.-
illusionJJ

これはまさに私が探していたものです。数字0〜9だけをチェックする簡単なもの。EditTextの宣言でフィルターを設定しましたが、変更または変更された場合に備えて、単純なプログラムによるチェックを行うこともできます。
jwehrle

127

Java 8ラムダ式。

String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );

4
メソッド参照も使用できます。someString.chars()。allMatch(Character :: isDigit)
Wienczny

3
素敵ですが、それでも、ほとんどすべての「ソリューション」として、車輪を再発明しています。また、(null)で失敗します(他のほとんどすべてと同様)。
qben 2016年

8
この答えは簡潔で、シンプルで読みやすいものです。ほぼ英語のように読むことができます-「chars all match digits」。サードパーティのライブラリは必要ありません。例外的なケースでは例外を使用しません。これは受け入れられる答えになるはずです。
アンディトーマス

14
「-1」で何を生み出すのか?
バラージュネメス

2
正解ではありません。数値文字列には、非数値文字(たとえば、「。」または「-」)を含めることができ、それでも完全に数値であることができます。たとえば、0.5、-1、1,000はすべてこの回答で失敗しますが、完全に数値です。
Simeon G

126

@CraigTPが彼の優れた回答で述べたように、文字列が数値であるかどうかをテストするために例外を使用することについても、同様のパフォーマンスの懸念があります。そのため、文字列を分割して使用しますjava.lang.Character.isDigit()

public static boolean isNumeric(String str)
{
    for (char c : str.toCharArray())
    {
        if (!Character.isDigit(c)) return false;
    }
    return true;
}

Javadocによると、はCharacter.isDigit(char)非ラテン数字を正しく認識します。パフォーマンスに関しては、Nが文字列の文字数である単純なN数の比較の方が、正規表現によるマッチングを行うよりも計算効率が高いと思います。

更新:Jean-FrançoisCorbettのコメントで指摘されているように、上記のコードは正の整数のみを検証し、これは私のユースケースの大部分をカバーしています。以下は、システムで使用されるデフォルトのロケールに従って10進数を正しく検証する更新されたコードです。小数点の区切り文字は文字列内で1回だけ発生すると想定しています。

public static boolean isStringNumeric( String str )
{
    DecimalFormatSymbols currentLocaleSymbols = DecimalFormatSymbols.getInstance();
    char localeMinusSign = currentLocaleSymbols.getMinusSign();

    if ( !Character.isDigit( str.charAt( 0 ) ) && str.charAt( 0 ) != localeMinusSign ) return false;

    boolean isDecimalSeparatorFound = false;
    char localeDecimalSeparator = currentLocaleSymbols.getDecimalSeparator();

    for ( char c : str.substring( 1 ).toCharArray() )
    {
        if ( !Character.isDigit( c ) )
        {
            if ( c == localeDecimalSeparator && !isDecimalSeparatorFound )
            {
                isDecimalSeparatorFound = true;
                continue;
            }
            return false;
        }
    }
    return true;
}

4
小数点記号もこれを失敗させませんか?
ジャン=フランソワ・コルベット

1
@Jean-FrançoisCorbett:良い点、小数点を受け入れる新しいコードでコードを更新しました。
イブラヒムアリエフ

2
-ve記号はこの機能に失敗しますか?
java_mouse 2013年

3
toCharArray()文字列は不変なので、呼び出すと文字列オブジェクトに配列のコピーが作成されます。おそらくcharAt(int index)、Stringオブジェクトのメソッドを直接使用する方が高速です。
マイクKucera 2014年

2
StringIndexOutOfBoundsException長さ0の文字列を渡したときに生成されます。修正可能if(str.length() == 0) return false;
samgak

43

GoogleのGuavaライブラリには、これを行うための優れたヘルパーメソッドが用意されていますInts.tryParse。同様に使用しますが、文字列が有効な整数に解析されない場合は、例外をスローするのInteger.parseIntではnullなく戻ります。これはintではなくIntegerを返すため、変換/オートボックス化してintに戻す必要があることに注意してください。

例:

String s1 = "22";
String s2 = "22.2";
Integer oInt1 = Ints.tryParse(s1);
Integer oInt2 = Ints.tryParse(s2);

int i1 = -1;
if (oInt1 != null) {
    i1 = oInt1.intValue();
}
int i2 = -1;
if (oInt2 != null) {
    i2 = oInt2.intValue();
}

System.out.println(i1);  // prints 22
System.out.println(i2);  // prints -1

ただし、現在のリリース-Guava r11-の時点では、まだ@Betaとマークされています。

私はそれをベンチマークしていません。ソースコードを見ると、多くの健全性チェックによるオーバーヘッドがありますが、結局、Character.digit(string.charAt(idx))上記の@Ibrahimの回答と似ていますが、少し異なります。それらの実装では、例外処理のオーバーヘッドが隠れていません。


これは、引数がnullの場合にNPEをスローすることに注意してください。
Vadzim

30

値を検証するために例外を使用しないでください。 Apache NumberUtilsのように、代わりにUtil libsを使用します。

NumberUtils.isNumber(myStringValue);

編集

文字列が0で始まる場合、NumberUtilsは値を16進数として解釈することに注意してください。

NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false

7
受け入れられた回答は、3年前にはすでにカバーされていましたNumber.isNumber()
アンディトーマス

私はそうは思いません。承認された回答が更新されたか、オペレーションが変更されました。受け入れられた回答はNumberUtilsをカバーしていなかったので、私の回答を追加しました。しかしコメントへの感謝
Goot

2
@Goot-受け入れられた回答の履歴は、Number.isNumber()12月24日17:01付けの回答の最初のバージョンから存在していたことを示しています。
アンディトーマス

@Goot、これはStringUtilsとは異なり、10進数値のチェックもカバーしているので、かなり良いです。
Heena Hussain

24

なぜ誰もが例外/正規表現ソリューションを求めているのですか?

私はほとんどの人がtry / catchを使用して問題ないことを理解できますが、頻繁に実行したい場合は...非常に負担になる可能性があります。

ここで行ったことは、正規表現、parseNumber()メソッド、および配列検索メソッドを使用して、どちらが最も効率的かを確認することでした。今回は整数のみを見ました。

public static boolean isNumericRegex(String str) {
    if (str == null)
        return false;
    return str.matches("-?\\d+");
}

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    char[] data = str.toCharArray();
    if (data.length <= 0)
        return false;
    int index = 0;
    if (data[0] == '-' && data.length > 1)
        index = 1;
    for (; index < data.length; index++) {
        if (data[index] < '0' || data[index] > '9') // Character.isDigit() can go here too.
            return false;
    }
    return true;
}

public static boolean isNumericException(String str) {
    if (str == null)
        return false;
    try {  
        /* int i = */ Integer.parseInt(str);
    } catch (NumberFormatException nfe) {  
        return false;  
    }
    return true;
}

私が得た速度の結果は:

Done with: for (int i = 0; i < 10000000; i++)...

With only valid numbers ("59815833" and "-59815833"):
    Array numeric took 395.808192 ms [39.5808192 ns each]
    Regex took 2609.262595 ms [260.9262595 ns each]
    Exception numeric took 428.050207 ms [42.8050207 ns each]
    // Negative sign
    Array numeric took 355.788273 ms [35.5788273 ns each]
    Regex took 2746.278466 ms [274.6278466 ns each]
    Exception numeric took 518.989902 ms [51.8989902 ns each]
    // Single value ("1")
    Array numeric took 317.861267 ms [31.7861267 ns each]
    Regex took 2505.313201 ms [250.5313201 ns each]
    Exception numeric took 239.956955 ms [23.9956955 ns each]
    // With Character.isDigit()
    Array numeric took 400.734616 ms [40.0734616 ns each]
    Regex took 2663.052417 ms [266.3052417 ns each]
    Exception numeric took 401.235906 ms [40.1235906 ns each]

With invalid characters ("5981a5833" and "a"):
    Array numeric took 343.205793 ms [34.3205793 ns each]
    Regex took 2608.739933 ms [260.8739933 ns each]
    Exception numeric took 7317.201775 ms [731.7201775 ns each]
    // With a single character ("a")
    Array numeric took 291.695519 ms [29.1695519 ns each]
    Regex took 2287.25378 ms [228.725378 ns each]
    Exception numeric took 7095.969481 ms [709.5969481 ns each]

With null:
    Array numeric took 214.663834 ms [21.4663834 ns each]
    Regex took 201.395992 ms [20.1395992 ns each]
    Exception numeric took 233.049327 ms [23.3049327 ns each]
    Exception numeric took 6603.669427 ms [660.3669427 ns each] if there is no if/null check

免責事項:これらの方法が100%最適化されているとは主張していません。これらはデータのデモンストレーションのためだけのものです

数が4文字以下で、すべての文字列が常に数である場合に限り、例外が発生します...その場合、なぜチェックさえしますか?

つまり、try / catchで無効な数値に頻繁に遭遇することは非常に苦痛です。私が常に従う重要なルールは、プログラムフローにtry / catchを使用しないことです。これがその理由の例です。

興味深いことに、単純なif char <0 || > 9は非常に簡単に記述でき、覚えやすく(複数の言語で機能するはずです)、ほとんどすべてのテストシナリオで成功しました。

唯一の欠点は、Integer.parseInt()がASCII以外の数値を処理する可能性があることを私が推測しているのに対し、配列検索メソッドは処理しないことです。


なぜ私が文字配列1を覚えやすいと言ったのか疑問に思う人のために、負の記号がないことがわかっている場合は、次のように凝縮されたもので簡単に回避できます。

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    for (char c : str.toCharArray())
        if (c < '0' || c > '9')
            return false;
    return true;

最後に、最後の注釈として、私はすべての投票が承認された、受け入れられた例の代入演算子に興味がありました。の割り当てに追加

double d = Double.parseDouble(...)

値を使用しないので役に立たないだけでなく、処理時間を浪費し、実行時間を数ナノ秒増加させます(テストで100〜200ミリ秒増加しました)。それは実際にはパフォーマンスを低下させるための余分な作業であるため、誰もがなぜそうするのかわかりません。

あなたはそれが最適化されるだろうと思うでしょう...多分私はバイトコードをチェックしてコンパイラが何をしているのかを見る必要があります。それはなぜそれがいつも私にとってより長く現れたのかを説明していませんが、それがどういうわけか最適化されているのであれば...したがって、何が起こっているのだろうと思います。注:より長く言うと、テストを10000000回繰り返し実行し、そのプログラムを複数回(10x +)実行すると、常に低速になることがわかりました。

編集:Character.isDigit()のテストを更新しました


4
これは毎回新しい正規表現をコンパイルしませんか?それは非常に効率的ではないようです。
Samuel Edwin Ward

1
@SamuelEdwinWardそれが私がこの投稿を作成した理由のすべてです...正規表現の例は他の人から提供された回答を使用し、それがいかに非効率的であるかを示しました。事前に事前コンパイルしてそれだけを使用して正規表現を試行した場合でも、時間差は次のとおりです。私が他の提供された人々から投稿した正規表現では2587ミリ秒、事前にコンパイルされた場合は950ミリ秒、数値配列(同じ文字列の1 milの反復用)。事前にコンパイルすると明らかに役立ちますが、悲しいことに、配列の方法よりもかなり劣っています...私が知らない非常識な最適化がない限り。

Regexが物事を高速化すると信じることは、ほぼ間違いです。一回限りの検索なら、ええ、それはわかります...しかし、効率的に書かれたコードが実際に正規表現を凌駕していることに気づきました。@Waterの素晴らしい投稿
Yo Apps

19
public static boolean isNumeric(String str)
{
    return str.matches("-?\\d+(.\\d+)?");
}

CraigTPの正規表現(上記を参照)では、いくつかの誤検知が発生します。たとえば、「23y4」は「。」であるため、数としてカウントされます。小数点以外の任意の文字に一致します。

また、先頭に「+」がある数字は拒否されます

これらの2つの小さな問題を回避する代替策は

public static boolean isNumeric(String str)
{
    return str.matches("[+-]?\\d*(\\.\\d+)?");
}

これは戻りますtrue、単一のプラスのため"+"またはマイナス"-"、とfalseのために"0."
user85421

単一のプラスまたはマイナスの良いキャッチ。「0」です。有効な番号ですか?
user872985 2011

"0."Double.parseDouble()JLS(§3.10.2)に従って有効であり、有効なリテラルです!
user85421 2011

正規表現の作成もコストがかかります。正規表現は一度作成して再利用する必要があります
Daniel Nuriyev

1
次のように変更する必要がありますmatches("-?\\d+([.]\\d+)?")
Bobs

14

与えられた文字列のすべての数字を( "")つまり空白で置き換えてみることができます。その後、文字列の長さがゼロの場合、与えられた文字列は数字のみを含むと言えます。[この回答が役に立った場合は、投票することを検討してください]例:

boolean isNumber(String str){
        if(str.length() == 0)
            return false; //To check if string is empty

        if(str.charAt(0) == '-')
            str = str.replaceFirst("-","");// for handling -ve numbers

        System.out.println(str);

        str = str.replaceFirst("\\.",""); //to check if it contains more than one decimal points

        if(str.length() == 0)
            return false; // to check if it is empty string after removing -ve sign and decimal point
        System.out.println(str);

        return str.replaceAll("[0-9]","").length() == 0;
    }

だから、""数が、ある"3.14"とは"-1"されていませんか?
Eric Duminil

明らかにすべての数値形式に当てはまるわけではありませんが、ここでは異なる考え方をする賛成票があります...元の考えがあなたの考えだった場合、それはそうです。
gbenroscience

12

使用できますNumberFormat#parse

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}

編集を提供しました-.getInstance()がありませんでした。+1これは私がこの質問を見つけるときに行った答えだったから。
8bitjunkie 2012

5
拡張可能に使用するとコストがかかる
ダニエルヌリエフ2014

1
の末尾に文字化けがある場合も通過しvalueます。
ブライアンホワイト

例外をログに記録しないと、ソナーの問題が発生します
jmhostalet 2018

1
これは、Double.parseDoubleが機能しなかった数値フォーマット0x0001で機能しました。+1
シーバス77


8

これが問題に対する私の答えです。

すべてのタイプのパーサーで任意の文字列を解析するために使用できるすべてをキャッチする便利なメソッド:isParsable(Object parser, String str)。パーサーは、Classまたはobjectです。これにより、作成したカスタムパーサーを使用できるようになり、次のようなシナリオで機能するはずです。

isParsable(Integer.class, "11");
isParsable(Double.class, "11.11");
Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");

メソッドの説明を含む私のコードを以下に示します。

import java.lang.reflect.*;

/**
 * METHOD: isParsable<p><p>
 * 
 * This method will look through the methods of the specified <code>from</code> parameter
 * looking for a public method name starting with "parse" which has only one String
 * parameter.<p>
 * 
 * The <code>parser</code> parameter can be a class or an instantiated object, eg:
 * <code>Integer.class</code> or <code>new Integer(1)</code>. If you use a
 * <code>Class</code> type then only static methods are considered.<p>
 * 
 * When looping through potential methods, it first looks at the <code>Class</code> associated
 * with the <code>parser</code> parameter, then looks through the methods of the parent's class
 * followed by subsequent ancestors, using the first method that matches the criteria specified
 * above.<p>
 * 
 * This method will hide any normal parse exceptions, but throws any exceptions due to
 * programmatic errors, eg: NullPointerExceptions, etc. If you specify a <code>parser</code>
 * parameter which has no matching parse methods, a NoSuchMethodException will be thrown
 * embedded within a RuntimeException.<p><p>
 * 
 * Example:<br>
 * <code>isParsable(Boolean.class, "true");<br>
 * isParsable(Integer.class, "11");<br>
 * isParsable(Double.class, "11.11");<br>
 * Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");<br>
 * isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");<br></code>
 * <p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @throws java.lang.NoSuchMethodException If no such method is accessible 
 */
public static boolean isParsable(Object parser, String str) {
    Class theClass = (parser instanceof Class? (Class)parser: parser.getClass());
    boolean staticOnly = (parser == theClass), foundAtLeastOne = false;
    Method[] methods = theClass.getMethods();

    // Loop over methods
    for (int index = 0; index < methods.length; index++) {
        Method method = methods[index];

        // If method starts with parse, is public and has one String parameter.
        // If the parser parameter was a Class, then also ensure the method is static. 
        if(method.getName().startsWith("parse") &&
            (!staticOnly || Modifier.isStatic(method.getModifiers())) &&
            Modifier.isPublic(method.getModifiers()) &&
            method.getGenericParameterTypes().length == 1 &&
            method.getGenericParameterTypes()[0] == String.class)
        {
            try {
                foundAtLeastOne = true;
                method.invoke(parser, str);
                return true; // Successfully parsed without exception
            } catch (Exception exception) {
                // If invoke problem, try a different method
                /*if(!(exception instanceof IllegalArgumentException) &&
                   !(exception instanceof IllegalAccessException) &&
                   !(exception instanceof InvocationTargetException))
                        continue; // Look for other parse methods*/

                // Parse method refuses to parse, look for another different method
                continue; // Look for other parse methods
            }
        }
    }

    // No more accessible parse method could be found.
    if(foundAtLeastOne) return false;
    else throw new RuntimeException(new NoSuchMethodException());
}


/**
 * METHOD: willParse<p><p>
 * 
 * A convienence method which calls the isParseable method, but does not throw any exceptions
 * which could be thrown through programatic errors.<p>
 * 
 * Use of {@link #isParseable(Object, String) isParseable} is recommended for use so programatic
 * errors can be caught in development, unless the value of the <code>parser</code> parameter is
 * unpredictable, or normal programtic exceptions should be ignored.<p>
 * 
 * See {@link #isParseable(Object, String) isParseable} for full description of method
 * usability.<p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @see #isParseable(Object, String) for full description of method usability 
 */
public static boolean willParse(Object parser, String str) {
    try {
        return isParsable(parser, str);
    } catch(Throwable exception) {
        return false;
    }
}

5

ASCII桁のみを含む、正の10進整数のみに一致させるには、次を使用します。

public static boolean isNumeric(String maybeNumeric) {
    return maybeNumeric != null && maybeNumeric.matches("[0-9]+");
}

5

try-catchを回避し、負の数と科学的表記を処理する、優れたパフォーマンスのアプローチ。

Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );

public static boolean isNumeric( String value ) 
{
    return value != null && PATTERN.matcher( value ).matches();
}

5

文字列が数値であるかどうかを確認するためのクラスを次に示します。また、数値文字列も修正します。

特徴:

  1. 不要なゼロを削除します["12.0000000"-> "12"]
  2. 不要なゼロを削除します["12.0580000"-> "12.058"]
  3. 数字以外の文字を削除します["12.00sdfsdf00"-> "12"]
  4. 負の文字列値を処理します["-12,020000"-> "-12.02"]
  5. 複数のドットを削除します["-12.0.20.000"-> "-12.02"]
  6. 追加のライブラリはなく、標準のJavaのみ

どうぞ...

public class NumUtils {
    /**
     * Transforms a string to an integer. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToInteger(String str) {
        String s = str;
        double d;
        d = Double.parseDouble(makeToDouble(s));
        int i = (int) (d + 0.5D);
        String retStr = String.valueOf(i);
        System.out.printf(retStr + "   ");
        return retStr;
    }

    /**
     * Transforms a string to an double. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToDouble(String str) {

        Boolean dotWasFound = false;
        String orgStr = str;
        String retStr;
        int firstDotPos = 0;
        Boolean negative = false;

        //check if str is null
        if(str.length()==0){
            str="0";
        }

        //check if first sign is "-"
        if (str.charAt(0) == '-') {
            negative = true;
        }

        //check if str containg any number or else set the string to '0'
        if (!str.matches(".*\\d+.*")) {
            str = "0";
        }

        //Replace ',' with '.'  (for some european users who use the ',' as decimal separator)
        str = str.replaceAll(",", ".");
        str = str.replaceAll("[^\\d.]", "");

        //Removes the any second dots
        for (int i_char = 0; i_char < str.length(); i_char++) {
            if (str.charAt(i_char) == '.') {
                dotWasFound = true;
                firstDotPos = i_char;
                break;
            }
        }
        if (dotWasFound) {
            String befDot = str.substring(0, firstDotPos + 1);
            String aftDot = str.substring(firstDotPos + 1, str.length());
            aftDot = aftDot.replaceAll("\\.", "");
            str = befDot + aftDot;
        }

        //Removes zeros from the begining
        double uglyMethod = Double.parseDouble(str);
        str = String.valueOf(uglyMethod);

        //Removes the .0
        str = str.replaceAll("([0-9])\\.0+([^0-9]|$)", "$1$2");

        retStr = str;

        if (negative) {
            retStr = "-"+retStr;
        }

        return retStr;

    }

    static boolean isNumeric(String str) {
        try {
            double d = Double.parseDouble(str);
        } catch (NumberFormatException nfe) {
            return false;
        }
        return true;
    }

}

5

正規表現マッチング

これは、より多くの検証と一致するアップグレードされた「CraigTP」正規表現の別の例です。

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  1. マイナス記号-は1つだけ使用でき、最初にある必要があります。
  2. 負符号の後に数字がなければなりません。
  3. 小数点記号.は1つしか使用できません。
  4. 小数点記号の後には数字が必要です。

正規表現テスト

1                  --                   **VALID**
1.                 --                   INVALID
1..                --                   INVALID
1.1                --                   **VALID**
1.1.1              --                   INVALID

-1                 --                   **VALID**
--1                --                   INVALID
-1.                --                   INVALID
-1.1               --                   **VALID**
-1.1.1             --                   INVALID

5

例外はコストがかかりますが、この場合、RegExにははるかに長い時間がかかります。以下のコードは、2つの関数の簡単なテストを示しています。1つは例外を使用し、もう1つは正規表現を使用しています。私のマシンでは、RegExバージョンは例外よりも10倍遅いです。

import java.util.Date;


public class IsNumeric {

public static boolean isNumericOne(String s) {
    return s.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.      
}

public static boolean isNumericTwo(String s) {
    try {
        Double.parseDouble(s);
        return true;
    } catch (Exception e) {
        return false;
    }
}

public static void main(String [] args) {

    String test = "12345.F";

    long before = new Date().getTime();     
    for(int x=0;x<1000000;++x) {
        //isNumericTwo(test);
        isNumericOne(test);
    }
    long after = new Date().getTime();

    System.out.println(after-before);

}

}

一般的に、この種のコードは、入力された入力などのチェックに使用されると思います。その場合、速度は考慮事項ではなく、例外をスローして数値または非数値をチェックするのと同じくらい醜いことをするのは間違っています。
user872985

そうでないかもしれない。入力された入力は通常、UIコンポーネントによってチェックされます。UIコンポーネントでは、値を送信する前にエラーをすぐに表示できます。パフォーマンスが重要な場合、大きな入力テキストファイルから文字列を検証する方が一般的です。ここでの私の回答の目標は、受け入れられた回答の「例外は遅い」という記述に対処することです。複雑な正規表現ははるかに高価です。そして、私のコードには「醜い投げ」はまったくありません-違反を検出するより速い方法です。先入れ先出し計算の方法では、入力に対して2つのパスを作成します。1つは検証用で、もう1つは変換です。
ChrisCantrell 2015

5

//以下のコードを確認してください

public static boolean isDigitsOnly(CharSequence str) {
    final int len = str.length();
    for (int i = 0; i < len; i++) {
        if (!Character.isDigit(str.charAt(i))) {
            return false;
        }
    }
    return true;
}

質問には、整数以外の値を含む可能性のある「数値」が含まれています。
rghome 2016

3
// only int
public static boolean isNumber(int num) 
{
    return (num >= 48 && c <= 57); // 0 - 9
}

// is type of number including . - e E 
public static boolean isNumber(String s) 
{
    boolean isNumber = true;
    for(int i = 0; i < s.length() && isNumber; i++) 
    {
        char c = s.charAt(i);
        isNumber = isNumber & (
            (c >= '0' && c <= '9') || (c == '.') || (c == 'e') || (c == 'E') || (c == '')
        );
    }
    return isInteger;
}

// is type of number 
public static boolean isInteger(String s) 
{
    boolean isInteger = true;
    for(int i = 0; i < s.length() && isInteger; i++) 
    {
        char c = s.charAt(i);
        isInteger = isInteger & ((c >= '0' && c <= '9'));
    }
    return isInteger;
}

public static boolean isNumeric(String s) 
{
    try
    {
        Double.parseDouble(s);
        return true;
    }
    catch (Exception e) 
    {
        return false;
    }
}

3

これは、このチェックの簡単な例です。

public static boolean isNumericString(String input) {
    boolean result = false;

    if(input != null && input.length() > 0) {
        char[] charArray = input.toCharArray();

        for(char c : charArray) {
            if(c >= '0' && c <= '9') {
                // it is a digit
                result = true;
            } else {
                result = false;
                break;
            }
        }
    }

    return result;
}

3

java.util.Scannerオブジェクトを使用できます。

public static boolean isNumeric(String inputData) {
      Scanner sc = new Scanner(inputData);
      return sc.hasNextInt();
    }

2

CraigTPのソリューションを修正して、科学表記とドットとコンマの両方を小数点記号として受け入れるようにしました

^-?\d+([,\.]\d+)?([eE]-?\d+)?$

var re = new RegExp("^-?\d+([,\.]\d+)?([eE]-?\d+)?$");
re.test("-6546"); // true
re.test("-6546355e-4456"); // true
re.test("-6546.355e-4456"); // true, though debatable
re.test("-6546.35.5e-4456"); // false
re.test("-6546.35.5e-4456.6"); // false

2

.NETのTry *アプローチが好きなのはそのためです。Javaのような従来のParseメソッドに加えて、TryParseメソッドもあります。私はJava構文(出力パラメーター?)が得意ではないので、以下をある種の疑似コードとして扱ってください。それでもコンセプトが明確になるはずです。

boolean parseInteger(String s, out int number)
{
    try {
        number = Integer.parseInt(myString);
        return true;
    } catch(NumberFormatException e) {
        return false;
    }
}

使用法:

int num;
if (parseInteger("23", out num)) {
    // Do something with num.
}

うん、Javaには「出力パラメーター」はなく、Integerラッパーは不変であるため(したがって、出力を保存する有効な参照として使用することはできません)、賢明な慣用的なオプションは、解析するとnullになる可能性があるIntegerオブジェクトを返すことです。失敗した。醜いオプションは、出力パラメーターとしてint [1]を渡すことです。
Fortran 2009

はい、Javaに出力パラメータがない理由についての説明を覚えています。しかし、整数化(必要に応じてnullとして)を返すことも問題ないと思いますが、ボクシング/アンボクシングに関するJavaのパフォーマンスについては知りません。
OregonGhost 2009

4
私は次の人と同じくらいC#が好きですが、Javaに機能が存在しない場合、Javaの質問に.NET C#コードスニペットを追加しても無駄です
Shane

例外をログに記録しないと、ソナーの問題が発生します
jmhostalet 2018

2

それを(つまりでInteger#parseInt)解析し、単に例外をキャッチします。=)

明確にするために:parseInt関数は、いずれにせよ(明らかに)数値を解析できるかどうかをチェックします。それでも、それを解析したい場合は、実際に解析を実行してもパフォーマンスに影響はありません。

それを解析したくない場合(または非常にまれにしか解析しない場合)は、もちろん別の方法で解析することもできます。


1
拡張可能に使用するとコストがかかる
ダニエルヌリエフ2014

例外をログに記録しないと、ソナーの問題が発生します
jmhostalet 2018

Double.parseDouble
Alex78191

2

Apache Commons Langの NumberUtils.isCreatable()を使用できます。

NumberUtils.isNumberは4.0で非推奨になるため、代わりにNumberUtils.isCreatable()を使用してください。


2

Java 8ストリーム、ラムダ式、関数型インターフェース

すべてのケースを処理(文字列null、文字列空など

String someString = null; // something="", something="123abc", something="123123"

boolean isNumeric = Stream.of(someString)
            .filter(s -> s != null && !s.isEmpty())
            .filter(Pattern.compile("\\D").asPredicate().negate())
            .mapToLong(Long::valueOf)
            .boxed()
            .findAny()
            .isPresent();

2

APIを使用せずに数値と小数をチェックするための条件をいくつか示しましたが、

固定長チェック1桁の数字

Character.isDigit(char)

固定長の数値を確認(長さが6であると想定)

String number = "132452";
if(number.matches("([0-9]{6})"))
System.out.println("6 digits number identified");

(4から6の長さを想定)の間のさまざまな長さの数値を確認してください

//  {n,m}  n <= length <= m
String number = "132452";
if(number.matches("([0-9]{4,6})"))
System.out.println("Number Identified between 4 to 6 length");

String number = "132";
if(!number.matches("([0-9]{4,6})"))
System.out.println("Number not in length range or different format");

(4から7の長さを想定)の間の可変長の10進数を確認します

//  It will not count the '.' (Period) in length
String decimal = "132.45";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1.12";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1234";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "-10.123";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "123..4";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "132";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "1.1";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

それが多くの人に役立つことを願っています。


2

他の回答に基づいて私は独自に作成しましたが、例外チェックでのパターンや解析は使用していません。

最大1つのマイナス記号をチェックし、最大1つの小数点をチェックします。

以下にいくつかの例とその結果を示します。

「1」、「-1」、「-1.5」、「-1.556」はtrueを返します

「1..5」、「1A.5」、「1.5D」、「-」、「-1」はfalseを返します

注:必要に応じてこれを変更してLocaleパラメーターを受け入れ、それをDecimalFormatSymbols.getInstance()呼び出しに渡して、現在のロケールの代わりに特定のロケールを使用できます。

 public static boolean isNumeric(final String input) {
    //Check for null or blank string
    if(input == null || input.isBlank()) return false;

    //Retrieve the minus sign and decimal separator characters from the current Locale
    final var localeMinusSign = DecimalFormatSymbols.getInstance().getMinusSign();
    final var localeDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();

    //Check if first character is a minus sign
    final var isNegative = input.charAt(0) == localeMinusSign;
    //Check if string is not just a minus sign
    if (isNegative && input.length() == 1) return false;

    var isDecimalSeparatorFound = false;

    //If the string has a minus sign ignore the first character
    final var startCharIndex = isNegative ? 1 : 0;

    //Check if each character is a number or a decimal separator
    //and make sure string only has a maximum of one decimal separator
    for (var i = startCharIndex; i < input.length(); i++) {
        if(!Character.isDigit(input.charAt(i))) {
            if(input.charAt(i) == localeDecimalSeparator && !isDecimalSeparatorFound) {
                isDecimalSeparatorFound = true;
            } else return false;
        }
    }
    return true;
}

1

機能する可能性のある2つの方法を次に示します。(例外を使用しない場合)。注:Javaはデフォルトで値渡しであり、文字列の値は文字列のオブジェクトデータのアドレスです。だから、あなたがやっているとき

stringNumber = stringNumber.replaceAll(" ", "");

入力値をスペースがないように変更しました。必要に応じて、その行を削除できます。

private boolean isValidStringNumber(String stringNumber)
{
    if(stringNumber.isEmpty())
    {
        return false;
    }

    stringNumber = stringNumber.replaceAll(" ", "");

    char [] charNumber = stringNumber.toCharArray();
    for(int i =0 ; i<charNumber.length ;i++)
    {
        if(!Character.isDigit(charNumber[i]))
        {
            return false;
        }
    }
    return true;
}

フロートを許可したい場合の別の方法を次に示します。この方法では、フォーム内の数値が1,123,123,123,123,123.123を通過できるようになっているとされています。

private boolean isValidStringTrueNumber(String stringNumber)
{
    if(stringNumber.isEmpty())
    {
        return false;
    }

    stringNumber = stringNumber.replaceAll(" ", "");
    int countOfDecimalPoint = 0;
    boolean decimalPointPassed = false;
    boolean commaFound = false;
    int countOfDigitsBeforeDecimalPoint = 0;
    int countOfDigitsAfterDecimalPoint =0 ;
    int commaCounter=0;
    int countOfDigitsBeforeFirstComma = 0;

    char [] charNumber = stringNumber.toCharArray();
    for(int i =0 ; i<charNumber.length ;i++)
    {
        if((commaCounter>3)||(commaCounter<0))
        {
            return false;
        }
        if(!Character.isDigit(charNumber[i]))//Char is not a digit.
        {
            if(charNumber[i]==',')
            {
                if(decimalPointPassed)
                {
                    return false;
                }
                commaFound = true;
                //check that next three chars are only digits.
                commaCounter +=3;
            }
            else if(charNumber[i]=='.')
            {
                decimalPointPassed = true;
                countOfDecimalPoint++;
            }
            else
            {
                return false;
            }
        }
        else //Char is a digit.
        {
            if ((commaCounter>=0)&&(commaFound))
            {
                if(!decimalPointPassed)
                {
                    commaCounter--;
                }
            }

            if(!commaFound)
            {
                countOfDigitsBeforeFirstComma++;
            }

            if(!decimalPointPassed)
            {
                countOfDigitsBeforeDecimalPoint++;
            }
            else
            {
                countOfDigitsAfterDecimalPoint++;
            }
        }
    }
    if((commaFound)&&(countOfDigitsBeforeFirstComma>3))
    {
        return false;
    }
    if(countOfDecimalPoint>1)
    {
        return false;
    }

    if((decimalPointPassed)&&((countOfDigitsBeforeDecimalPoint==0)||(countOfDigitsAfterDecimalPoint==0)))
    {
        return false;
    }
    return true;
}

ああ、いい質問です。これは通常のタイプの整数でのみ機能すると思います。このメソッドは、入力電話番号をフィルタリングして番号をカウントするために最初に作成されました。
XForCE07 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.