Wie kann am besten überprüft werden, ob ein String in Java eine Ganzzahl darstellt?

214

Normalerweise verwende ich die folgende Redewendung, um zu überprüfen, ob ein String in eine Ganzzahl konvertiert werden kann.

public boolean isInteger( String input ) {
    try {
        Integer.parseInt( input );
        return true;
    }
    catch( Exception e ) {
        return false;
    }
}

Ist es nur ich oder scheint das ein bisschen hackisch? Was ist ein besserer Weg?


In meiner Antwort (mit Benchmarks, basierend auf der früheren Antwort von CodingWithSpike ) erfahren Sie , warum ich meine Position umgekehrt und Jonas Klemmings Antwort auf dieses Problem akzeptiert habe . Ich denke, dieser ursprüngliche Code wird von den meisten Leuten verwendet, weil er schneller zu implementieren und wartbarer ist, aber um Größenordnungen langsamer, wenn nicht ganzzahlige Daten bereitgestellt werden.

Bill die Eidechse
quelle
Was halten Sie von RegExp für die Lösung?
Akshay Pethani

Antworten:

171

Wenn Sie sich nicht mit möglichen Überlaufproblemen befassen, wird diese Funktion etwa 20 bis 30 Mal schneller ausgeführt als die Verwendung Integer.parseInt().

public static boolean isInteger(String str) {
    if (str == null) {
        return false;
    }
    int length = str.length();
    if (length == 0) {
        return false;
    }
    int i = 0;
    if (str.charAt(0) == '-') {
        if (length == 1) {
            return false;
        }
        i = 1;
    }
    for (; i < length; i++) {
        char c = str.charAt(i);
        if (c < '0' || c > '9') {
            return false;
        }
    }
    return true;
}
Jonas K.
quelle
50
(c <= '/' || c> = ':') sieht etwas seltsam aus. Ich hätte verwendet (c <'0' || c> '9') ... sind die Operatoren <= und> = in Java schneller?
Anonym
3
Warum nicht Regex verwenden? Ist die Rückgabe von str.matches ("^ -? \\ d + $") nicht identisch mit dem obigen Code?
Maglob
15
Ich würde diese Methode oder die ursprüngliche Methode aus der Frage vor Regex verwenden. Dies ist für die Leistung die ursprüngliche Methode für die Geschwindigkeit der Implementierung und die reine Wartbarkeit. Die Regex-Lösung hat nichts zu bieten.
Bill the Lizard
4
Ich mache mir Sorgen um einen Überlauf, aber diese Methode kann für BigInts angepasst werden und ist dennoch viel schneller als andere Methoden. Für den Fall, dass sich jemand fragt, warum ich mich so sehr um ein so einfaches Problem bemühe, erstelle ich eine Bibliothek, um bei der Lösung von Project Euler-Problemen zu helfen.
Bill the Lizard
1
Wenn Sie sich Sorgen machen, ob Sie die Zeichenfolge tatsächlich in ein int oder long analysieren können, müssen Sie auch überprüfen, ob die Ganzzahl, die die Zeichenfolge darstellt, tatsächlich in diese Datentypen passt.
Jonas K
65

Sie haben es, aber Sie sollten nur fangen NumberFormatException.

Ovidiu Pacurar
quelle
7
Ja, es wird als schlechte Form angesehen, mehr Ausnahmen zu fangen, als Sie brauchen.
Chris
Du hast recht. NFE ist die einzige, die geworfen werden kann, aber es ist immer noch eine schlechte Angewohnheit, sich darauf einzulassen.
Bill the Lizard
Ich denke, eine NPE kann ausgelöst werden, wenn die Eingabe null ist. Daher sollte Ihre Methode dies wahrscheinlich explizit behandeln, je nachdem, wie Sie möchten.
Dov Wasserman
@Dov: Du hast Recht, NPE und NFE sollten beide explizit gefangen werden.
Bill the Lizard
Diese Antwort sollte die wahre Antwort auf diese Frage sein.
Breedly
40

Habe einen schnellen Benchmark gemacht. Ausnahmen sind eigentlich nicht so teuer, es sei denn, Sie beginnen, mehrere Methoden zurückzusetzen, und die JVM muss viel Arbeit leisten, um den Ausführungsstapel einzurichten. Wenn sie in der gleichen Methode bleiben, sind sie keine schlechten Darsteller.

 public void RunTests()
 {
     String str = "1234567890";

     long startTime = System.currentTimeMillis();
     for(int i = 0; i < 100000; i++)
         IsInt_ByException(str);
     long endTime = System.currentTimeMillis();
     System.out.print("ByException: ");
     System.out.println(endTime - startTime);

     startTime = System.currentTimeMillis();
     for(int i = 0; i < 100000; i++)
         IsInt_ByRegex(str);
     endTime = System.currentTimeMillis();
     System.out.print("ByRegex: ");
     System.out.println(endTime - startTime);

     startTime = System.currentTimeMillis();
     for(int i = 0; i < 100000; i++)
         IsInt_ByJonas(str);
     endTime = System.currentTimeMillis();
     System.out.print("ByJonas: ");
     System.out.println(endTime - startTime);
 }

 private boolean IsInt_ByException(String str)
 {
     try
     {
         Integer.parseInt(str);
         return true;
     }
     catch(NumberFormatException nfe)
     {
         return false;
     }
 }

 private boolean IsInt_ByRegex(String str)
 {
     return str.matches("^-?\\d+$");
 }

 public boolean IsInt_ByJonas(String str)
 {
     if (str == null) {
             return false;
     }
     int length = str.length();
     if (length == 0) {
             return false;
     }
     int i = 0;
     if (str.charAt(0) == '-') {
             if (length == 1) {
                     return false;
             }
             i = 1;
     }
     for (; i < length; i++) {
             char c = str.charAt(i);
             if (c <= '/' || c >= ':') {
                     return false;
             }
     }
     return true;
 }

Ausgabe:

ByException: 31

ByRegex: 453 (Hinweis: Das Muster wird jedes Mal neu kompiliert.)

ByJonas: 16

Ich stimme zu, dass die Lösung von Jonas K auch die robusteste ist. Sieht aus wie er gewinnt :)

CodingWithSpike
quelle
13
Tolle Idee, alle drei zu vergleichen. Um den Regex- und Jonas-Methoden gerecht zu werden, sollten Sie mit nicht ganzzahligen Zeichenfolgen testen, da dort die Integer.parseInt-Methode wirklich langsamer wird.
Bill the Lizard
4
Entschuldigung, aber dieser Regex-Test ist nicht gut. (1) Sie müssen keine Regex - Engine Check machen ^und $zweites Mal in matchesgesamter Zeichenfolge muss Regex Übereinstimmen, (2) str.matchesjedes Mal wird seine eigenen erstellen , Patterndie teuer ist. Aus Leistungsgründen sollten wir ein solches Muster nur einmal außerhalb dieser Methode erstellen und innerhalb verwenden. (3) Wir können auch nur ein Matcher-Objekt erstellen und es verwenden reset(CharSequence), um Benutzerdaten zu übergeben und das matches()Ergebnis zurückzugeben.
Pshemo
So etwas private final Matcher m = Pattern.compile("-?\\d+").matcher(""); private boolean byRegex(String str) { return m.reset(str).matches(); }sollte eine bessere Leistung haben.
Pshemo
@Pshemo Integer.valueOf ("1") und Integer.valueOf ("1") lösen beide eine Ausnahme aus, sodass die Überprüfung auf ^ und $ sinnvoll erscheint.
Cquezel
1
@cquezel Ja, aber es ist nicht erforderlich, da matcheses hinzugefügt wird ^und $implizit. Schauen Sie sich das Ergebnis von " 123".matches("\\d+")und an "123".matches("\\d+"). Du wirst sehen falseund true. falsewird zurückgegeben, da die Zeichenfolge mit einem Leerzeichen beginnt, das verhindert, dass sie vollständig mit dem regulären Ausdruck übereinstimmt.
Pshemo
37

Da es die Möglichkeit gibt, dass die Leute immer noch hierher kommen und nach den Benchmarks gegen Regex voreingenommen sind ... Also werde ich eine aktualisierte Version des Benchmarks mit einer kompilierten Version des Regex geben. Was im Gegensatz zu den vorherigen Benchmarks zeigt, dass die Regex-Lösung tatsächlich eine konstant gute Leistung aufweist.

Von Bill the Lizard kopiert und mit der kompilierten Version aktualisiert:

private final Pattern pattern = Pattern.compile("^-?\\d+$");

public void runTests() {
    String big_int = "1234567890";
    String non_int = "1234XY7890";

    long startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByException(big_int);
    long endTime = System.currentTimeMillis();
    System.out.print("ByException - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByException(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByException - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByRegex(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByRegex - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByRegex(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByRegex - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
            IsInt_ByCompiledRegex(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByCompiledRegex - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
            IsInt_ByCompiledRegex(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByCompiledRegex - non-integer data: ");
    System.out.println(endTime - startTime);


    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByJonas(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByJonas - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
            IsInt_ByJonas(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByJonas - non-integer data: ");
    System.out.println(endTime - startTime);
}

private boolean IsInt_ByException(String str)
{
    try
    {
        Integer.parseInt(str);
        return true;
    }
    catch(NumberFormatException nfe)
    {
        return false;
    }
}

private boolean IsInt_ByRegex(String str)
{
    return str.matches("^-?\\d+$");
}

private boolean IsInt_ByCompiledRegex(String str) {
    return pattern.matcher(str).find();
}

public boolean IsInt_ByJonas(String str)
{
    if (str == null) {
            return false;
    }
    int length = str.length();
    if (length == 0) {
            return false;
    }
    int i = 0;
    if (str.charAt(0) == '-') {
            if (length == 1) {
                    return false;
            }
            i = 1;
    }
    for (; i < length; i++) {
            char c = str.charAt(i);
            if (c <= '/' || c >= ':') {
                    return false;
            }
    }
    return true;
}

Ergebnisse:

ByException - integer data: 45
ByException - non-integer data: 465

ByRegex - integer data: 272
ByRegex - non-integer data: 131

ByCompiledRegex - integer data: 45
ByCompiledRegex - non-integer data: 26

ByJonas - integer data: 8
ByJonas - non-integer data: 2
Felipe
quelle
1
Die ByCompiledRegex-Zeit muss das Kompilieren des Regex in die Zeitmessung einbeziehen.
Martin Carney
2
@ MartinCarney Ich habe es modifiziert und die Musterkompilierung verglichen. Natürlich ist meine CPU / JIT schneller, aber wenn ich sie zurück interpoliere, ist die Kompilierungszeit 336.
Tedder42
2
um klar zu sein, dass 336 (ms) das ist, was passiert, wenn die Musterkompilierung 100.000 Mal durchgeführt wird, genau wie alle anderen Zeilen. Mit der Implikation, dass es nur einmal gemacht wird, ist seine Zeit im Grunde Null.
Tedder42
Vielen Dank, dass Sie den Datensatz direkt auf die kompilierten Regex-Zeiten eingestellt haben.
LarsH
Vielleicht "^[+-]?\\d+$"wäre es sogar noch besser.
Adam
34
org.apache.commons.lang.StringUtils.isNumeric 

obwohl Javas Standardbibliothek solche Dienstprogrammfunktionen wirklich vermisst

Ich denke, dass Apache Commons ein "Muss" für jeden Java-Programmierer ist

Schade, dass es noch nicht auf Java5 portiert ist

Łukasz Bownik
quelle
1
Das einzige Problem dabei ist der Überlauf: SI gibt Ihnen immer noch +1 für die Erwähnung von commons-lang :)
javamonkey79
2
Das andere Problem sind negative Zahlen, aber ich auch +1, da dieser Ansatz meiner Ansicht nach einer guten Lösung am nächsten kommt.
Sandris
22

Dies hängt teilweise davon ab, was Sie unter "kann in eine Ganzzahl konvertiert werden" verstehen.

Wenn Sie meinen "kann in Java in ein int konvertiert werden", dann ist die Antwort von Jonas ein guter Anfang, aber beendet den Job nicht ganz. Es würde zum Beispiel 99999999999999999999999999999999 passieren. Ich würde den normalen Try / Catch-Aufruf aus Ihrer eigenen Frage am Ende der Methode hinzufügen.

Bei den zeichenweisen Überprüfungen werden Fälle "überhaupt keine Ganzzahl" effizient zurückgewiesen, sodass "es ist eine Ganzzahl, aber Java kann sie nicht verarbeiten" -Fälle von der langsameren Ausnahmeroute abgefangen werden. Sie könnten dies auch von Hand tun, aber es wäre viel komplizierter.

Jon Skeet
quelle
17

Nur ein Kommentar zu Regexp. Jedes hier angegebene Beispiel ist falsch!. Wenn Sie Regexp verwenden möchten, vergessen Sie nicht, dass das Kompilieren des Musters viel Zeit in Anspruch nimmt. Dies:

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

und auch das:

Pattern.matches("-?\\d+", input);

bewirkt bei jedem Methodenaufruf eine Kompilierung des Musters. Um es richtig zu verwenden, folgen Sie:

import java.util.regex.Pattern;

/**
 * @author Rastislav Komara
 */
public class NaturalNumberChecker {
    public static final Pattern PATTERN = Pattern.compile("^\\d+$");

    boolean isNaturalNumber(CharSequence input) {
        return input != null && PATTERN.matcher(input).matches();
    }
}
Rastislav Komara
quelle
5
Sie können die Leistung etwas steigern, indem Sie den Matcher auch im Voraus erstellen und ihn mit seiner reset () -Methode auf die Eingabe anwenden.
Alan Moore
13

Es gibt eine Guavenversion:

import com.google.common.primitives.Ints;

Integer intValue = Ints.tryParse(stringValue);

Es wird null zurückgegeben, anstatt eine Ausnahme auszulösen, wenn die Zeichenfolge nicht analysiert werden kann.

abalcerek
quelle
3
Beste Antwort IMHO. Verwenden Sie gut getestete Bibliotheken, anstatt Ihre eigene Lösung zusammenzustellen. (Siehe auch die Diskussion hier .)
Olivier Cailloux
12

Ich habe den Code aus der Antwort von Rally25 kopiert und einige Tests für nicht ganzzahlige Daten hinzugefügt. Die Ergebnisse sprechen zweifellos für die von Jonas Klemming veröffentlichte Methode. Die Ergebnisse für die Ausnahmemethode, die ich ursprünglich veröffentlicht habe, sind ziemlich gut, wenn Sie ganzzahlige Daten haben, aber sie sind die schlechtesten, wenn Sie dies nicht tun, während die Ergebnisse für die RegEx-Lösung (auf die ich wetten werde, dass viele Leute sie verwenden) waren durchweg schlecht. In Felipes Antwort finden Sie ein kompiliertes Regex-Beispiel, das viel schneller ist.

public void runTests()
{
    String big_int = "1234567890";
    String non_int = "1234XY7890";

    long startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByException(big_int);
    long endTime = System.currentTimeMillis();
    System.out.print("ByException - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByException(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByException - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByRegex(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByRegex - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByRegex(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByRegex - non-integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByJonas(big_int);
    endTime = System.currentTimeMillis();
    System.out.print("\nByJonas - integer data: ");
    System.out.println(endTime - startTime);

    startTime = System.currentTimeMillis();
    for(int i = 0; i < 100000; i++)
        IsInt_ByJonas(non_int);
    endTime = System.currentTimeMillis();
    System.out.print("ByJonas - non-integer data: ");
    System.out.println(endTime - startTime);
}

private boolean IsInt_ByException(String str)
{
    try
    {
        Integer.parseInt(str);
        return true;
    }
    catch(NumberFormatException nfe)
    {
        return false;
    }
}

private boolean IsInt_ByRegex(String str)
{
    return str.matches("^-?\\d+$");
}

public boolean IsInt_ByJonas(String str)
{
    if (str == null) {
            return false;
    }
    int length = str.length();
    if (length == 0) {
            return false;
    }
    int i = 0;
    if (str.charAt(0) == '-') {
            if (length == 1) {
                    return false;
            }
            i = 1;
    }
    for (; i < length; i++) {
            char c = str.charAt(i);
            if (c <= '/' || c >= ':') {
                    return false;
            }
    }
    return true;
}

Ergebnisse:

ByException - integer data: 47
ByException - non-integer data: 547

ByRegex - integer data: 390
ByRegex - non-integer data: 313

ByJonas - integer data: 0
ByJonas - non-integer data: 16
Bill die Eidechse
quelle
6

Dies ist kürzer, aber kürzer ist nicht unbedingt besser (und es werden keine ganzzahligen Werte erfasst, die außerhalb des Bereichs liegen, wie in Danatels Kommentar ausgeführt ):

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

Persönlich würde ich, da die Implementierung in einer Hilfsmethode weggezerrt ist und die Korrektheit die Länge übertrumpft, einfach so etwas wie das machen, was Sie haben (abzüglich des Abfangens der Basisklasse Exceptionanstatt NumberFormatException).

Jonny Buchanan
quelle
1
Und vielleicht ist \\ d {1,10}, obwohl nicht perfekt, besser als \\ d +, um Java Integers zu fangen
Maglob
6

Sie können die Übereinstimmungsmethode der Zeichenfolgenklasse verwenden. Das [0-9] repräsentiert alle Werte, die es sein kann, das + bedeutet, dass es mindestens ein Zeichen lang sein muss, und das * bedeutet, dass es null oder mehr Zeichen lang sein kann.

boolean isNumeric = yourString.matches("[0-9]+"); // 1 or more characters long, numbers only
boolean isNumeric = yourString.matches("[0-9]*"); // 0 or more characters long, numbers only
Kaitie
quelle
1
Nb dies stimmt nicht mit "+10" oder "-10" überein), was normalerweise als gültige ganze Zahlen enthalten wäre
Tim Wintle
4

Wie wäre es mit:

return Pattern.matches("-?\\d+", input);
Kristian
quelle
Was ist mit der Ganzzahl 9999999999999999999999999999999999?
Danatel
Vergessen Sie nicht, nach dem negativen Vorzeichen zu suchen.
Jeremy Ruten
Müssen Sie nicht den Anfang und das Ende des regulären Ausdrucks verankern, damit Sie "aaa-1999zzz" nicht bestehen?
Tim Howland
2
Tim, wenn Sie eine der match () -Methoden aufrufen (String, Pattern und Matcher haben jeweils eine), muss der reguläre Ausdruck mit der gesamten Eingabe übereinstimmen, wodurch Anker überflüssig werden. Um eine Übereinstimmung zu finden, wie sie von den meisten anderen Regex-Varianten definiert wird, müssen Sie Matcher # find () verwenden.
Alan Moore
4

Dies ist eine Java 8-Variante der Antwort von Jonas Klemming:

public static boolean isInteger(String str) {
    return str != null && str.length() > 0 &&
         IntStream.range(0, str.length()).allMatch(i -> i == 0 && (str.charAt(i) == '-' || str.charAt(i) == '+')
                  || Character.isDigit(str.charAt(i)));
}

Testcode:

public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    Arrays.asList("1231231", "-1232312312", "+12313123131", "qwqe123123211", "2", "0000000001111", "", "123-", "++123",
            "123-23", null, "+-123").forEach(s -> {
        System.out.printf("%15s %s%n", s, isInteger(s));
    });
}

Ergebnisse des Testcodes:

        1231231 true
    -1232312312 true
   +12313123131 true
  qwqe123123211 false
              2 true
  0000000001111 true
                false
           123- false
          ++123 false
         123-23 false
           null false
          +-123 false
gil.fernandes
quelle
3

Sie überprüfen nur NumberFormatException : -

 String value="123";
 try  
 {  
    int s=Integer.parseInt(any_int_val);
    // do something when integer values comes 
 }  
 catch(NumberFormatException nfe)  
 {  
          // do something when string values comes 
 }  
Duggu
quelle
3

Wenn Ihr String-Array reine Ganzzahlen und Strings enthält, sollte der folgende Code funktionieren. Sie müssen nur das erste Zeichen betrachten. zB ["4", "44", "abc", "77", "bond"]

if (Character.isDigit(string.charAt(0))) {
    //Do something with int
}
realPK
quelle
3

Sie können auch die Scanner- Klasse und hasNextInt () verwenden. Auf diese Weise können Sie auch andere Typen wie Floats usw. testen.

Matthew Schinckel
quelle
Diese Antwort gab mir eine Erinnerung, die ich brauchte. Ich habe völlig vergessen, dass Scanner eine solche Funktion hat. T-up
Hubro
2

Wenn Sie überprüfen möchten, ob die Zeichenfolge eine Ganzzahl darstellt, die in einen int-Typ passt, habe ich die Antwort der Jonas geringfügig geändert, sodass Zeichenfolgen, die Ganzzahlen darstellen, die größer als Integer.MAX_VALUE oder kleiner als Integer.MIN_VALUE sind, jetzt zurückgegeben werden falsch. Beispiel: "3147483647" gibt false zurück, da 3147483647 größer als 2147483647 ist, und "-2147483649" gibt ebenfalls false zurück, da -2147483649 kleiner als -2147483648 ist.

public static boolean isInt(String s) {
  if(s == null) {
    return false;
  }
  s = s.trim(); //Don't get tricked by whitespaces.
  int len = s.length();
  if(len == 0) {
    return false;
  }
  //The bottom limit of an int is -2147483648 which is 11 chars long.
  //[note that the upper limit (2147483647) is only 10 chars long]
  //Thus any string with more than 11 chars, even if represents a valid integer, 
  //it won't fit in an int.
  if(len > 11) {
    return false;
  }
  char c = s.charAt(0);
  int i = 0;
  //I don't mind the plus sign, so "+13" will return true.
  if(c == '-' || c == '+') {
    //A single "+" or "-" is not a valid integer.
    if(len == 1) {
      return false;
    }
    i = 1;
  }
  //Check if all chars are digits
  for(; i < len; i++) {
    c = s.charAt(i);
    if(c < '0' || c > '9') {
      return false;
    }
  }
  //If we reached this point then we know for sure that the string has at
  //most 11 chars and that they're all digits (the first one might be a '+'
  // or '-' thought).
  //Now we just need to check, for 10 and 11 chars long strings, if the numbers
  //represented by the them don't surpass the limits.
  c = s.charAt(0);
  char l;
  String limit;
  if(len == 10 && c != '-' && c != '+') {
    limit = "2147483647";
    //Now we are going to compare each char of the string with the char in
    //the limit string that has the same index, so if the string is "ABC" and
    //the limit string is "DEF" then we are gonna compare A to D, B to E and so on.
    //c is the current string's char and l is the corresponding limit's char
    //Note that the loop only continues if c == l. Now imagine that our string
    //is "2150000000", 2 == 2 (next), 1 == 1 (next), 5 > 4 as you can see,
    //because 5 > 4 we can guarantee that the string will represent a bigger integer.
    //Similarly, if our string was "2139999999", when we find out that 3 < 4,
    //we can also guarantee that the integer represented will fit in an int.
    for(i = 0; i < len; i++) {
      c = s.charAt(i);
      l = limit.charAt(i);
      if(c > l) {
        return false;
      }
      if(c < l) {
        return true;
      }
    }
  }
  c = s.charAt(0);
  if(len == 11) {
    //If the first char is neither '+' nor '-' then 11 digits represent a 
    //bigger integer than 2147483647 (10 digits).
    if(c != '+' && c != '-') {
      return false;
    }
    limit = (c == '-') ? "-2147483648" : "+2147483647";
    //Here we're applying the same logic that we applied in the previous case
    //ignoring the first char.
    for(i = 1; i < len; i++) {
      c = s.charAt(i);
      l = limit.charAt(i);
      if(c > l) {
        return false;
      }
      if(c < l) {
        return true;
      }
    }
  }
  //The string passed all tests, so it must represent a number that fits
  //in an int...
  return true;
}

quelle
1
Können Sie bitte Ihre Antwort bearbeiten und erklären, wie sie die zuvor erwähnte Antwort verbessert?
Gilles Gouaillardet
Danke für die tolle Antwort. Aber "123", dh 123 zusammen mit dem Leerzeichen, wird als gültige ganze Zahl betrachtet.
Saikrishna Radarapu
1
@ SaikrishnaRadarapu Sie verwenden, trim()so dass dies eindeutig eine absichtliche Designentscheidung ist.
Guildenstern
2

Sie können Apache-Utils ausprobieren

NumberUtils.isCreatable(myText)

Sehen Sie den Javadoc hier

Borjab
quelle
1
Scheint, dass diese Methode im Link zur neuesten Version veraltet ist . Anscheinend sollten Sie isCreateable(String)stattdessen verwenden.
Guildenstern
Aktualisiert. Danke @Guildenstern
Borjab
1

Sie müssen wahrscheinlich auch den Anwendungsfall berücksichtigen:

Wenn Sie die meiste Zeit erwarten, dass Zahlen gültig sind, verursacht das Abfangen der Ausnahme nur dann einen Leistungsaufwand, wenn Sie versuchen, ungültige Zahlen zu konvertieren. Während einige Aufruf isInteger()Methode und wandeln dann unter Verwendung Integer.parseInt()wird immer für gültige Zahlen Ursache einer Leistungsaufwand - die Saiten zweimal analysiert werden, einmal durch die Prüfung und einmal durch die Umwandlung.

mobra66
quelle
1

Dies ist eine Modifikation von Jonas 'Code, die prüft, ob sich die Zeichenfolge innerhalb des Bereichs befindet, der in eine Ganzzahl umgewandelt werden soll.

public static boolean isInteger(String str) {
    if (str == null) {
        return false;
    }
    int length = str.length();
    int i = 0;

    // set the length and value for highest positive int or lowest negative int
    int maxlength = 10;
    String maxnum = String.valueOf(Integer.MAX_VALUE);
    if (str.charAt(0) == '-') { 
        maxlength = 11;
        i = 1;
        maxnum = String.valueOf(Integer.MIN_VALUE);
    }  

    // verify digit length does not exceed int range
    if (length > maxlength) { 
        return false; 
    }

    // verify that all characters are numbers
    if (maxlength == 11 && length == 1) {
        return false;
    }
    for (int num = i; num < length; num++) {
        char c = str.charAt(num);
        if (c < '0' || c > '9') {
            return false;
        }
    }

    // verify that number value is within int range
    if (length == maxlength) {
        for (; i < length; i++) {
            if (str.charAt(i) < maxnum.charAt(i)) {
                return true;
            }
            else if (str.charAt(i) > maxnum.charAt(i)) {
                return false;
            }
        }
    }
    return true;
}
Wayne
quelle
1
sieht gut aus, aber für die letzte for-Schleife muss i auf Null zurückgesetzt werden (oder auf 1, wenn eine negative Zahl vorliegt), da die Schleife, die prüft, ob jede Ziffer eine Zahl ist, dazu führt, dass i die Zeichenfolgenlänge ist, daher die letzte for-Schleife wird nie laufen. Ich würde auch die Java-Konstanten Integer.MAX_VALUE und Integer.MIN_VALUE anstelle der magischen Zahlen verwenden.
Tim der Verzauberer
@ TimtheEnchanter Danke für die Vorschläge, ich habe sie komplett übersehen. In meiner Bearbeitung habe ich eine neue Variable in der ersten for-Schleife verwendet, um die zusätzliche if-Anweisung zu vermeiden.
Wayne
1

Wenn Sie die Android-API verwenden, können Sie Folgendes verwenden:

TextUtils.isDigitsOnly(str);
timxyz
quelle
1

Andere Option:

private boolean isNumber(String s) {
    boolean isNumber = true;
    for (char c : s.toCharArray()) {
        isNumber = isNumber && Character.isDigit(c);
    }
    return isNumber;
}
Gabriel Kaffka
quelle
0
is_number = true;
try {
  Integer.parseInt(mystr)
} catch (NumberFormatException  e) {
  is_number = false;
}
Ricardo Acras
quelle
5
Dies ist genau das, wonach das Poster fragt.
Martin Carney
0

Was Sie getan haben, funktioniert, aber Sie sollten es wahrscheinlich nicht immer so überprüfen. Das Auslösen von Ausnahmen sollte "außergewöhnlichen" Situationen vorbehalten sein (möglicherweise passt dies jedoch in Ihren Fall) und ist in Bezug auf die Leistung sehr kostspielig.

lucas
quelle
Sie sind nur teuer, wenn sie geworfen werden.
Bill the Lizard
0
Number number;
try {
    number = NumberFormat.getInstance().parse("123");
} catch (ParseException e) {
    //not a number - do recovery.
    e.printStackTrace();
}
//use number
Ran Biron
quelle
0

Dies würde nur für positive ganze Zahlen funktionieren.

public static boolean isInt(String str) {
    if (str != null && str.length() != 0) {
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isDigit(str.charAt(i))) return false;
        }
    }
    return true;        
}
callejero
quelle
4
Willkommen bei stackoverflow. Lesen Sie unbedingt die vorherigen Antworten und Kommentare, bevor Sie einen alten Thread wiederbeleben. Diese Methode (und mögliche Nachteile) wurden bereits diskutiert.
Leigh
0

Das funktioniert bei mir. Einfach identifizieren, ob ein String ein Grundelement oder eine Zahl ist.

private boolean isPrimitive(String value){
        boolean status=true;
        if(value.length()<1)
            return false;
        for(int i = 0;i<value.length();i++){
            char c=value.charAt(i);
            if(Character.isDigit(c) || c=='.'){

            }else{
                status=false;
                break;
            }
        }
        return status;
    }
Niroshan Abeywickrama
quelle
0

Um nach allen int-Zeichen zu suchen, können Sie einfach ein doppeltes Negativ verwenden.

if (! searchString.matches ("[^ 0-9] + $")) ...

[^ 0-9] + $ prüft, ob es Zeichen gibt, die nicht ganzzahlig sind. Daher schlägt der Test fehl, wenn er wahr ist. Nur NICHT das und du wirst wahr beim Erfolg.

Roger F. Gay
quelle
Nein, Sie haben dies eindeutig nicht getestet. Dies gibt nur dann true zurück, wenn sich irgendwo in der Zeichenfolge eine Ziffer befindet, nicht wenn die Zeichenfolge nur aus Ziffern besteht. Die matchesMethode stimmt mit der gesamten Zeichenfolge überein, nicht nur mit einem Teil davon.
Dawood ibn Kareem
Sie erhalten nicht den doppelten negativen Teil.
Roger F. Gay
Nun, ich bekomme kein doppeltes Negativ. Das funktioniert einfach nicht. Wenn Sie eine Mischung aus Ziffern und Buchstaben haben, geht dies in den ifBlock. Es sollte nicht.
Dawood ibn Kareem
0

Finden Sie dies kann hilfreich sein:

public static boolean isInteger(String self) {
    try {
        Integer.valueOf(self.trim());
        return true;
    } catch (NumberFormatException nfe) {
        return false;
    }
}
Shellbye
quelle
0

Ich glaube , dass es Null - Risiko in eine Ausnahme ausgeführt wird , weil , wie Sie unten sehen Sie können immer sicher analysieren intzuString und nicht umgekehrt.

So:

  1. Sie überprüfen, ob jeder Zeichenschlitz in Ihrer Zeichenfolge mit mindestens einem der Zeichen {"0", "1", "2", "3", "4", "5", "6", "7", übereinstimmt. "8", "9"} .

    if(aString.substring(j, j+1).equals(String.valueOf(i)))
  2. Sie summieren alle Zeiten, die Sie in den Slots auf die oben genannten Zeichen gestoßen sind.

    digits++;
  3. Und schließlich überprüfen Sie , ob die Zeiten, zu denen Sie auf Ganzzahlen als Zeichen gestoßen sind, der Länge der angegebenen Zeichenfolge entsprechen.

    if(digits == aString.length())

Und in der Praxis haben wir:

    String aString = "1234224245";
    int digits = 0;//count how many digits you encountered
    for(int j=0;j<aString.length();j++){
        for(int i=0;i<=9;i++){
            if(aString.substring(j, j+1).equals(String.valueOf(i)))
                    digits++;
        }
    }
    if(digits == aString.length()){
        System.out.println("It's an integer!!");
        }
    else{
        System.out.println("It's not an integer!!");
    }
    
    String anotherString = "1234f22a4245";
    int anotherDigits = 0;//count how many digits you encountered
    for(int j=0;j<anotherString.length();j++){
        for(int i=0;i<=9;i++){
            if(anotherString.substring(j, j+1).equals(String.valueOf(i)))
                    anotherDigits++;
        }
    }
    if(anotherDigits == anotherString.length()){
        System.out.println("It's an integer!!");
        }
    else{
        System.out.println("It's not an integer!!");
    }

Und die Ergebnisse sind:

Es ist eine ganze Zahl !!

Es ist keine ganze Zahl !!

Ebenso können Sie überprüfen, ob a Stringein floatoder ein ist, doubleaber in diesen Fällen müssen Sie nur auf eines stoßen . (Punkt) in der Zeichenfolge und natürlich prüfen, ob digits == (aString.length()-1)

Auch hier besteht kein Risiko, dass eine Parsing-Ausnahme auftritt. Wenn Sie jedoch eine bekannte Zeichenfolge analysieren möchten, die eine Zahl enthält (z. B. int- Datentyp), müssen Sie zunächst prüfen, ob sie in den Datentyp passt. Sonst musst du es besetzen.

ich hoffe ich habe geholfen

mark_infinite
quelle