So überprüfen Sie, ob ein String in Java numerisch ist


886

Wie würden Sie überprüfen, ob ein String eine Zahl ist, bevor Sie ihn analysieren?


36
Alle mit regulären Ausdrücken vorgeschlagenen Lösungen funktionieren nicht für Hexadezimalzahlen.
Oscar Castiblanco

Wenn Sie eine Nullzeichenfolge in der Funktion "Übereinstimmungen (...)" übergeben, wird eine NullPointer-Ausnahme ausgelöst.
Hitesh Sahu

In der Antwort von Max Malysh finden Sie eine übersichtliche Java 8-Lösung ohne Bibliotheken von Drittanbietern.
Andy Thomas

@HiteshSahu Null-Strings scheinen in der neuesten Version (einschließlich Java 6.x und 7.x)
ordnungsgemäß behandelt zu werden

Bei allen vorgeschlagenen Lösungen können Integer.parseInt()Mobiltelefonnummern nicht analysiert werden NumberFormatException.
Kein Fehler

Antworten:


691

Mit Apache Commons Lang 3.5 und höher: NumberUtils.isCreatableoder StringUtils.isNumeric.

Mit Apache Commons Lang 3.4 und darunter: NumberUtils.isNumberoder StringUtils.isNumeric.

Sie können auch verwenden, StringUtils.isNumericSpacewas truefür leere Zeichenfolgen zurückgibt und interne Leerzeichen in der Zeichenfolge ignoriert. Eine andere Möglichkeit ist die Verwendung, bei NumberUtils.isParsableder grundsätzlich überprüft wird, ob die Nummer gemäß Java analysiert werden kann. (Die verknüpften Javadocs enthalten detaillierte Beispiele für jede Methode.)


59
StringUtils.isNumeric()wahrscheinlich wäre dies hier nicht angebracht, da nur geprüft wird, ob die Zeichenfolge eine Folge von Ziffern ist. Wäre in Ordnung für die meisten Ints, aber nicht für Zahlen mit Dezimalstellen, Gruppentrennzeichen usw.
Jeff Mercado

42
Erfinden Sie das Rad neu, weil Sie keine ganze Bibliothek einschließen, weil Sie eine 3-Zeilen-Funktion an einer Stelle benötigen.
Dalvarezmartinez1

12
Lohnt es sich wirklich, eine ganze Bibliothek für diese Funktion hinzuzufügen ? Natürlich, wenn es mit anderen Dingen verwendet wird, ist das großartig, aber es ist wahrscheinlich übertrieben, wenn man bedenkt, dass die Leute dies in einer Codezeile gelöst haben.
Wasser

7
Funktioniert nicht mit Negativen. Und die Hälfte aller Zahlen ist negativ, also .....
Paul Draper

6
@PaulDraper: Sie haben Recht, StringUtilsunterstützt keine führenden Zeichen, aber Sie sollten überprüfen NumberUtils.isCreatable, es unterstützt Negative richtig.
Palacsint

904

Dies erfolgt in der Regel mit einer einfachen benutzerdefinierten Funktion (dh Roll-Your-Own-Funktion "isNumeric").

Etwas wie:

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

Wenn Sie diese Funktion jedoch häufig aufrufen und erwarten, dass viele der Überprüfungen fehlschlagen, weil sie keine Zahl sind, ist die Leistung dieses Mechanismus nicht besonders gut, da Sie sich darauf verlassen, dass für jeden Fehler Ausnahmen ausgelöst werden. Das ist eine ziemlich teure Operation.

Ein alternativer Ansatz kann darin bestehen, einen regulären Ausdruck zu verwenden, um die Gültigkeit einer Zahl zu überprüfen:

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

Seien Sie jedoch vorsichtig mit dem oben genannten RegEx-Mechanismus, da er fehlschlägt, wenn Sie nicht-arabische Ziffern verwenden (dh andere Ziffern als 0 bis 9). Dies liegt daran, dass der "\ d" -Teil des RegEx nur mit [0-9] übereinstimmt und international nicht numerisch bekannt ist. (Vielen Dank an OregonGhost für diesen Hinweis!)

Oder eine andere Alternative ist die Verwendung des in Java integrierten Objekts java.text.NumberFormat, um festzustellen, ob sich die Parserposition nach dem Parsen der Zeichenfolge am Ende der Zeichenfolge befindet. Wenn dies der Fall ist, können wir davon ausgehen, dass die gesamte Zeichenfolge numerisch ist:

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
Stimmt \ d in Java Regex nur mit lateinischen Ziffern überein? Wenn es sich um .NET-Regexe handelt, treten Probleme mit anderen (z. B. arabischen) Ziffern auf, wie hier erläutert: blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
OregonGhost

3
Die numberFormatter-Lösung ist wahrscheinlich nur unwesentlich besser als die NumberFormatException-Lösung. Ich vermute, der beste Weg ist, Regex eins zu verwenden.
Chii

11
Beachten Sie, dass der .in Ihrer Regex angegebene Wert mit jedem Zeichen übereinstimmt, nicht nur mit dem Dezimaltrennzeichen.
jqno

9
+1 für die Realisierung der Kosten für Versuch / Fang. Dies ist eigentlich ein schrecklicher Ansatz, der auf lange Sicht für die wiederholte Verwendung verwendet werden muss, aber in Java bleiben wir wirklich dabei.
Demongolem

5
Beachten Sie, dass es keine "lateinischen Ziffern" gibt und die Ziffern 0-9 tatsächlich arabische Ziffern sind. Die Leute sind wahrscheinlich mit römischen Ziffern vertraut, die von Leuten verwendet wurden, die Latein sprachen, in der Form I, II, III, IV, V, VI usw. en.wikipedia.org/wiki/Arabic_numerals ; en.wikipedia.org/wiki/Roman_numerals
Dantiston

152

Wenn Sie auf Android sind, sollten Sie verwenden:

android.text.TextUtils.isDigitsOnly(CharSequence str)

Dokumentation finden Sie hier

halte es einfach . Meist kann jeder "neu programmieren" (das Gleiche).


4
@ kape123 :) sicher, dass "123.456" keine Ziffern enthält.
Ahmed Alejo

8
Hinweis: Dies führt zu NPE für die Null-Eingabe. Funktioniert auch nicht mit negativen Zahlen oder Dezimalstellen.
gMale

2
Ich mag das!! Ich denke, das ist absolut für Ziffern. Nicht für .,-
IllusionJJ

Das ist genau das, wonach ich gesucht habe. Etwas Einfaches, um nur nach den Ziffern 0-9 zu suchen. Ich habe einen Filter in der Deklaration meines EditText festgelegt, aber nur für den Fall, dass dieser später geändert oder ersetzt wird, ist es schön, auch eine einfache programmatische Überprüfung durchzuführen.
jwehrle

127

Java 8 Lambda-Ausdrücke.

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

4
Sie können auch eine Methodenreferenz verwenden: someString.chars (). AllMatch (Character :: isDigit)
Wienczny

3
Schön, aber es erfindet das Rad immer noch neu, wie fast alle "Lösungen" hier. Scheitert auch bei 'null' (wie fast alle anderen).
Qben

8
Diese Antwort ist kurz, einfach und lesbar. Sie können es fast wie Englisch lesen - "Zeichen alle übereinstimmen Ziffern". Es sind keine Bibliotheken von Drittanbietern erforderlich. In nicht außergewöhnlichen Fällen werden keine Ausnahmen verwendet. Dies sollte die akzeptierte Antwort werden.
Andy Thomas

14
Was wird es für "-1" produzieren?
Balázs Németh

2
Nicht die richtige Antwort. Eine numerische Zeichenfolge kann nicht numerische Zeichen (z. B. "." Oder "-") enthalten und dennoch perfekt numerisch sein. Zum Beispiel schlagen 0,5, -1 und 1.000 mit dieser Antwort fehl und sind dennoch perfekt numerisch.
Simeon G

125

Wie @CraigTP in seiner hervorragenden Antwort erwähnt hatte, habe ich ähnliche Leistungsprobleme bei der Verwendung von Ausnahmen, um zu testen, ob die Zeichenfolge numerisch ist oder nicht. Also spalte ich den String und benutze ihn java.lang.Character.isDigit().

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

Nach dem Javadoc , Character.isDigit(char)wird richtig erkennt nicht-lateinische Ziffern. In Bezug auf die Leistung denke ich, dass eine einfache Anzahl von N Vergleichen, bei denen N die Anzahl der Zeichen in der Zeichenfolge ist, rechnerisch effizienter wäre als ein Regex-Abgleich.

UPDATE: Wie von Jean-François Corbett im Kommentar ausgeführt, würde der obige Code nur positive ganze Zahlen validieren, was den Großteil meines Anwendungsfalls abdeckt. Im Folgenden finden Sie den aktualisierten Code, mit dem Dezimalzahlen gemäß dem in Ihrem System verwendeten Standardgebietsschema korrekt überprüft werden. Dabei wird davon ausgegangen, dass das Dezimaltrennzeichen nur einmal in der Zeichenfolge vorkommt.

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
Wird das Dezimaltrennzeichen nicht auch dazu führen, dass dies fehlschlägt?
Jean-François Corbett

1
@ Jean-FrançoisCorbett: Guter Punkt, ich habe den Code mit einem neueren Code aktualisiert, der Dezimaltrennzeichen akzeptiert.
Ibrahim Arief

2
Fehlschlägt -ve sign diese Funktion?
Java_Maus

3
Durch Aufrufen toCharArray()wird eine Kopie des Arrays im String-Objekt erstellt, da Strings unveränderlich sind. Wahrscheinlich schneller, um die charAt(int index)Methode direkt für das String-Objekt zu verwenden.
Mike Kucera

2
Wird generiert, StringIndexOutOfBoundsExceptionwenn eine Zeichenfolge mit der Länge 0 übergeben wird. Kann mitif(str.length() == 0) return false;
samgak

43

Die Guava-Bibliothek von Google bietet hierfür eine nützliche Hilfsmethode : Ints.tryParse. Sie verwenden es wie, Integer.parseIntaber es gibt zurück, nullanstatt eine Ausnahme auszulösen, wenn die Zeichenfolge nicht auf eine gültige Ganzzahl analysiert wird. Beachten Sie, dass Integer und nicht int zurückgegeben wird. Sie müssen es also zurück in int konvertieren / autoboxen.

Beispiel:

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

Ab der aktuellen Version - Guava r11 - ist es jedoch immer noch mit @Beta gekennzeichnet.

Ich habe es nicht bewertet. Wenn man sich den Quellcode ansieht, entsteht ein gewisser Aufwand durch viele Überprüfungen Character.digit(string.charAt(idx))der geistigen Gesundheit , aber am Ende verwenden sie die Antwort von @Ibrahim oben, ähnlich, aber etwas anders. Es gibt keine Ausnahmebehandlung bei der Implementierung.


Beachten Sie, dass dies NPE auslösen würde, falls das Argument null ist.
Vadzim

30

Verwenden Sie keine Ausnahmen, um Ihre Werte zu überprüfen. Verwenden Sie stattdessen Util-Bibliotheken wie Apache NumberUtils:

NumberUtils.isNumber(myStringValue);

Bearbeiten :

Bitte beachten Sie, dass NumberUtils Ihren Wert als hexadezimal interpretiert, wenn Ihre Zeichenfolge mit einer 0 beginnt.

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

7
Die akzeptierte Antwort, drei Jahre zuvor, wurde bereits behandelt Number.isNumber().
Andy Thomas

Das glaube ich nicht. Es wurde die akzeptierte Antwort aktualisiert oder geändert. Ich erinnere mich, dass die akzeptierte Antwort NumberUtils nicht abdeckte, deshalb habe ich meine Antwort hinzugefügt. Aber danke für den Kommentar
Goot

2
@Goot - Der Verlauf der akzeptierten Antwort zeigt, dass Number.isNumber()ab der ersten Version der Antwort vom 24. September 12 um 17:01 Uhr vorhanden war.
Andy Thomas

@Goot, das ist ziemlich gut, da es im Gegensatz zu StringUtils auch die Dezimalwertprüfung abdeckt.
Heena Hussain

24

Warum drängen alle auf Ausnahme- / Regex-Lösungen?

Ich kann zwar verstehen, dass die meisten Leute mit try / catch gut zurechtkommen, aber wenn Sie es häufig tun möchten, kann es extrem anstrengend sein.

Was ich hier getan habe, war die Verwendung des regulären Ausdrucks, der parseNumber () -Methoden und der Array-Suchmethode, um festzustellen, welche die effizienteste war. Dieses Mal habe ich nur ganzzahlige Zahlen betrachtet.

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

Die Ergebnisse in Geschwindigkeit, die ich bekam, waren:

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

Haftungsausschluss: Ich behaupte nicht, dass diese Methoden zu 100% optimiert sind, sondern nur zur Demonstration der Daten

Ausnahmen wurden nur dann gewonnen, wenn die Zahl 4 Zeichen oder weniger beträgt und jede Zeichenfolge immer eine Zahl ist. In welchem ​​Fall sollte überhaupt ein Scheck ausgestellt werden?

Kurz gesagt, es ist äußerst schmerzhaft, wenn Sie beim Versuch / Fang häufig auf ungültige Zahlen stoßen, was Sinn macht. Eine wichtige Regel, die ich immer befolge, ist, NIEMALS try / catch für den Programmfluss zu verwenden . Dies ist ein Beispiel dafür.

Interessanterweise ist das einfache if char <0 || > 9 war extrem einfach zu schreiben, leicht zu merken (und sollte in mehreren Sprachen funktionieren) und gewinnt fast alle Testszenarien.

Der einzige Nachteil ist, dass Integer.parseInt () möglicherweise Nicht-ASCII-Zahlen verarbeitet, während dies bei der Array-Suchmethode nicht der Fall ist.


Für diejenigen, die sich fragen, warum ich gesagt habe, dass es einfach ist, sich an das Zeichenarray zu erinnern. Wenn Sie wissen, dass es keine negativen Vorzeichen gibt, können Sie leicht mit etwas davonkommen, das sich wie folgt verdichtet:

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;

Abschließend war ich neugierig auf den Zuweisungsoperator im akzeptierten Beispiel mit allen abgegebenen Stimmen. Hinzufügen in der Zuordnung von

double d = Double.parseDouble(...)

ist nicht nur nutzlos, da Sie den Wert nicht einmal verwenden, sondern verschwendet auch Verarbeitungszeit und erhöht die Laufzeit um einige Nanosekunden (was zu einer Erhöhung der Tests um 100 bis 200 ms führte). Ich kann nicht verstehen, warum das jemand tun würde, da es tatsächlich zusätzliche Arbeit ist, um die Leistung zu reduzieren.

Sie würden denken, das wäre optimiert ... obwohl ich vielleicht den Bytecode überprüfen und sehen sollte, was der Compiler tut. Das erklärt nicht, warum es für mich immer länger war, wenn es irgendwie optimiert ist ... deshalb frage ich mich, was los ist. Als Hinweis: Mit länger meine ich, den Test für 10000000 Iterationen auszuführen und dieses Programm mehrmals (10x +) auszuführen, hat immer gezeigt, dass es langsamer ist.

BEARBEITEN: Ein Test für Character.isDigit () wurde aktualisiert.


4
Kompiliert dies nicht jedes Mal einen neuen regulären Ausdruck? Das scheint nicht sehr effizient zu sein.
Samuel Edwin Ward

1
@SamuelEdwinWard Das ist der ganze Grund, warum ich diesen Beitrag verfasst habe ... Das Regex-Beispiel verwendete die Antworten anderer Leute und zeigte, wie ineffizient es ist. Selbst wenn Sie versuchen, Regex zu erstellen, indem Sie es vorab kompilieren und nur verwenden, betragen die Zeitunterschiede: 2587 ms für den Regex, den ich von anderen bereitgestellten Personen gepostet habe, 950 ms, wenn er vorab kompiliert wurde, 144 ms, wenn Sie ihn als ausführen numerisches Array (für 1-mil-Iterationen derselben Zeichenfolge). Vorab zu kompilieren würde natürlich helfen, aber leider ist es dem Array-Weg immer noch ziemlich unterlegen ... es sei denn, es gibt eine verrückte Optimierung, von der ich nichts weiß.
Wasser

Zu glauben, dass Regex die Dinge schneller macht, ist fast ein Trugschluss. Wenn es eine einmalige Suche ist, ja, ich verstehe ... aber ich habe festgestellt, dass effizient geschriebener Code Regex tatsächlich genug übertrifft, um Sie zu schockieren! Großartiger Beitrag @Water
Yo Apps

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

Der reguläre Ausdruck von CraigTP (siehe oben) führt zu einigen falsch positiven Ergebnissen. ZB "23y4" wird als Zahl gezählt, weil '.' Entspricht einem beliebigen Zeichen, das nicht dem Dezimalpunkt entspricht.

Außerdem wird jede Zahl mit einem führenden '+' abgelehnt.

Eine Alternative, die diese beiden kleinen Probleme vermeidet, ist

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

Dies wird truefür ein einzelnes Plus "+"oder Minus "-"und falsefür"0."
user85421

Guter Fang für das einzelne Plus oder Minus. Ist "0". eine gültige Nummer?
user872985

"0."ist gültig für Double.parseDouble()und ist ein gültiges Literal gemäß JLS ( §3.10.2 )!
user85421

Das Erstellen regulärer Ausdrücke ist ebenfalls kostspielig. Der reguläre Ausdruck muss einmal erstellt und wiederverwendet werden
Daniel Nuriyev

1
Sie sollten es ändern inmatches("-?\\d+([.]\\d+)?")
Bobs

14

Wir können versuchen, alle Zahlen aus der angegebenen Zeichenfolge durch ("") zu ersetzen, dh ein Leerzeichen. Wenn danach die Länge der Zeichenfolge Null ist, können wir sagen, dass die angegebene Zeichenfolge nur Zahlen enthält. [Wenn Sie diese Antwort hilfreich fanden, ziehen Sie bitte eine Abstimmung in Betracht] Beispiel:

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

Also ""ist eine Nummer aber "3.14"und "-1"nicht?
Eric Duminil

Offensichtlich gilt dies nicht für alle Zahlenformen, aber hier ist eine Gegenstimme für ein anderes Denken ... wenn der ursprüngliche Gedanke dein war, das heißt.
Gbenroscience

12

Sie können verwenden NumberFormat#parse:

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

Angebotene Bearbeitung - .getInstance () fehlte. +1, da dies die Antwort war, mit der ich diese Frage gefunden habe.
8bitjunkie

5
Kostspielig bei erweiterbarer Verwendung
Daniel Nuriyev

1
Es wird auch übergeben, wenn am Ende von Müllzeichen stehen value.
Brian White

Es würde ein
Sonarproblem verursachen,

1
Dies funktionierte für das Zahlenformat 0x0001, bei dem Double.parseDouble nicht funktionierte. +1
Seabass77


8

Hier war meine Antwort auf das Problem.

Eine Catch-All-Convenience-Methode, mit der Sie einen beliebigen String mit einem beliebigen Parsertyp analysieren können : isParsable(Object parser, String str). Der Parser kann ein Classoder ein sein object. Auf diese Weise können Sie auch benutzerdefinierte Parser verwenden, die Sie geschrieben haben und die für jedes Szenario funktionieren sollten, z.

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");

Hier ist mein Code mit Methodenbeschreibungen.

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

Verwenden Sie Folgendes, um nur positive Basis-Zehn-Ganzzahlen abzugleichen, die nur ASCII-Ziffern enthalten:

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

5

Ein leistungsfähiger Ansatz, der das Fangen von Versuchen vermeidet und mit negativen Zahlen und wissenschaftlicher Notation umgeht.

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

Hier ist meine Klasse, um zu überprüfen, ob eine Zeichenfolge numerisch ist. Es werden auch numerische Zeichenfolgen korrigiert:

Eigenschaften:

  1. Entfernt unnötige Nullen ["12.0000000" -> "12"]
  2. Entfernt unnötige Nullen ["12.0580000" -> "12.058"]
  3. Entfernt nicht numerische Zeichen ["12.00sdfsdf00" -> "12"]
  4. Behandelt negative Zeichenfolgenwerte ["-12,020000" -> "-12.02"]
  5. Entfernt mehrere Punkte ["-12.0.20.000" -> "-12.02"]
  6. Keine zusätzlichen Bibliotheken, nur Standard-Java

Bitte schön...

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

Regex-Matching

Hier ist ein weiteres Beispiel für ein aktualisiertes "CraigTP" -Regex-Matching mit mehr Validierungen.

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  1. Nur ein negatives Vorzeichen ist -erlaubt und muss am Anfang stehen.
  2. Nach dem negativen Vorzeichen muss eine Ziffer stehen.
  3. Nur ein Dezimalzeichen .erlaubt.
  4. Nach dem Dezimalzeichen muss eine Ziffer stehen.

Regex-Test

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

Ausnahmen sind teuer, aber in diesem Fall dauert der RegEx viel länger. Der folgende Code zeigt einen einfachen Test von zwei Funktionen - eine mit Ausnahmen und eine mit Regex. Auf meinem Computer ist die RegEx-Version zehnmal langsamer als die Ausnahme.

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);

}

}

Im Allgemeinen denke ich, dass diese Art von Code verwendet wird, um Dinge wie eingegebene Eingaben zu überprüfen. In diesem Fall spielt Geschwindigkeit keine Rolle, und es ist falsch, etwas so Hässliches zu tun, als eine Ausnahme auszulösen, um nach Nummern oder Nicht-Nummern zu suchen.
user872985

Vielleicht nicht. Die eingegebene Eingabe wird im Allgemeinen von der UI-Komponente überprüft, wobei Fehler sofort angezeigt werden können, bevor der Wert gesendet wird. Es ist möglicherweise üblicher, Zeichenfolgen aus großen Eingabetextdateien zu überprüfen - wo es auf die Leistung ankommt. Das Ziel meiner Antwort hier ist es, die Aussage "Ausnahmen sind langsam" in der akzeptierten Antwort anzusprechen. Komplexer Regex ist viel teurer. Und es gibt überhaupt keinen "hässlichen Wurf" in meinem Code - nur eine schnellere Möglichkeit, Verstöße zu erkennen. Mit einem Check-First-Then-Calculate-Ansatz führen Sie zwei Durchgänge durch die Eingabe durch: einen zum Überprüfen und einen zum Konvertieren.
ChrisCantrell

5

// Bitte überprüfen Sie den folgenden Code

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

Die Frage lautet "numerisch" und kann nicht ganzzahlige Werte enthalten.
rghome

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

Dies ist ein einfaches Beispiel für diese Prüfung:

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

Sie können das Objekt java.util.Scanner verwenden.

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

2

Ich habe die Lösung von CraigTP so geändert, dass auch die wissenschaftliche Notation sowie Punkt und Komma als Dezimaltrennzeichen akzeptiert werden

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

Beispiel

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

Deshalb mag ich den Try * -Ansatz in .NET. Zusätzlich zu der traditionellen Parse-Methode, die der Java-Methode ähnelt, gibt es auch eine TryParse-Methode. Ich bin nicht gut in der Java-Syntax (out-Parameter?), Behandeln Sie daher Folgendes als eine Art Pseudocode. Es sollte das Konzept jedoch klar machen.

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

Verwendungszweck:

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

Ja, es gibt keine "out-Parameter" in Java. Da der Integer-Wrapper unveränderlich ist (daher nicht als gültige Referenz zum Speichern der Ausgabe verwendet werden kann), besteht die sinnvolle idiomatische Option darin, ein Integer-Objekt zurückzugeben, das bei der Analyse null sein könnte gescheitert. Eine hässlichere Option könnte darin bestehen, ein int [1] als Ausgabeparameter zu übergeben.
Fortan

Ja, ich erinnere mich an eine Diskussion darüber, warum Java keine Ausgabeparameter hat. Aber die Rückgabe einer Ganzzahl (bei Bedarf als Null) wäre auch in Ordnung, obwohl ich nichts über die Leistung von Java in Bezug auf das Boxen / Entpacken weiß.
OregonGhost

4
Ich mag C # genauso wie der nächste Typ, aber es nützt nichts, ein .NET C # -Code-Snippet für eine Java-Frage hinzuzufügen, wenn die Funktionen in Java nicht vorhanden sind
Shane

Es würde ein
Sonarproblem verursachen,

2

Analysieren Sie es (dh mit Integer#parseInt) und fangen Sie einfach die Ausnahme ab. =)

Zur Verdeutlichung: Die Funktion parseInt prüft, ob sie die Nummer auf jeden Fall (offensichtlich) analysieren kann, und wenn Sie sie trotzdem analysieren möchten, werden Sie keinen Leistungseinbruch erleiden, wenn Sie die Analyse tatsächlich durchführen.

Wenn Sie es nicht analysieren möchten (oder sehr, sehr selten analysieren möchten), möchten Sie es natürlich natürlich anders machen.


1
Kostspielig bei erweiterbarer Verwendung
Daniel Nuriyev

Es würde ein
Sonarproblem verursachen,

Double.parseDouble
Alex78191


2

Java 8 Stream, Lambda-Ausdruck, funktionale Schnittstelle

Alle behandelten Fälle ( Zeichenfolge null, Zeichenfolge leer usw. )

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

Ich habe einige Bedingungen dargestellt, um Zahlen und Dezimalstellen ohne Verwendung einer API zu überprüfen.

Überprüfen Sie die 1-stellige Nummer der Fixlänge

Character.isDigit(char)

Überprüfen Sie die Nummer der festen Länge (Angenommen, die Länge beträgt 6).

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

Überprüfen Sie die Anzahl der unterschiedlichen Längen zwischen (Nehmen Sie eine Länge von 4 bis 6 an).

//  {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");

Überprüfen Sie die Dezimalzahl für die unterschiedliche Länge zwischen (Annahme einer Länge von 4 bis 7).

//  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");

Hoffe, es wird vielen helfen.


2

Basierend auf anderen Antworten habe ich meine eigenen geschrieben und es werden keine Muster oder Parsing mit Ausnahmeprüfung verwendet.

Es wird auf maximal ein Minuszeichen und auf maximal einen Dezimalpunkt geprüft.

Hier einige Beispiele und deren Ergebnisse:

"1", "-1", "-1,5" und "-1,556" geben true zurück

"1..5", "1A.5", "1.5D", "-" und "--1" geben false zurück

Hinweis: Bei Bedarf können Sie dies ändern, um einen Locale-Parameter zu akzeptieren und diesen an die DecimalFormatSymbols.getInstance () -Aufrufe zu übergeben, um ein bestimmtes Gebietsschema anstelle des aktuellen zu verwenden.

 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

Hier sind zwei Methoden, die funktionieren könnten. (Ohne Ausnahmen zu verwenden). Hinweis: Java ist standardmäßig ein Pass-by-Wert, und der Wert eines Strings ist die Adresse der Objektdaten des Strings. Also, wenn du es tust

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

Sie haben den Eingabewert so geändert, dass keine Leerzeichen mehr vorhanden sind. Sie können diese Zeile entfernen, wenn Sie möchten.

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

Hier ist eine andere Methode für den Fall, dass Sie Floats zulassen möchten. Diese Methode erlaubt angeblich, dass Zahlen in der Form 1.123.123.123.123.123.123 übergeben. Ich habe es gerade gemacht, und ich denke, es müssen weitere Tests durchgeführt werden, um sicherzustellen, dass es funktioniert.

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

Oh, gute Frage. Ich denke, dass dies nur normale Ganzzahlen funktioniert. Die Methode wurde ursprünglich erstellt, um eingegebene Telefonnummern zu filtern und Nummern zu zählen.
XForCE07
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.