Jaki jest najlepszy sposób sprawdzenia, czy String reprezentuje liczbę całkowitą w Javie?

214

Zwykle używam następującego idiomu, aby sprawdzić, czy String można przekonwertować na liczbę całkowitą.

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

Czy to tylko ja, czy wydaje się to nieco hackerskie? Jaki jest lepszy sposób?


Zobacz moją odpowiedź (z wzorców, na podstawie wcześniejszej odpowiedzi przez CodingWithSpike ), aby zobaczyć, dlaczego mam odwrócić moją pozycję i zaakceptowane odpowiedź Jonas Klemming za tego problemu. Myślę, że ten oryginalny kod będzie używany przez większość ludzi, ponieważ jest szybszy do wdrożenia i łatwiejszy w utrzymaniu, ale jest o rząd wielkości wolniejszy, gdy dostarczane są dane niecałkowite.

Bill jaszczurka
źródło
Jaki masz pomysł na RegExp dla rozwiązania?
Akshay Pethani

Odpowiedzi:

171

Jeśli nie przejmujesz się potencjalnymi problemami z przepełnieniem, ta funkcja będzie działać około 20-30 razy szybciej niż przy użyciu 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
źródło
50
(c <= '/' || c> = ':') jest nieco dziwny. Użyłbym (c <'0' || c> '9') ... czy operatory <= i> = są szybsze w Javie?
Anonimowy
3
Dlaczego nie użyć wyrażenia regularnego? Czy zwracane ciągi str. („^ -? \\ d + $”) nie są identyczne z powyższym kodem?
Maglob
15
Użyłbym tej metody lub oryginalnej metody z pytania przed wyrażeniem regularnym. To pod względem wydajności, oryginalna metoda szybkości wdrożenia i zwykła łatwość konserwacji. Rozwiązanie wyrażenia regularnego nic na to nie pozwala.
Bill the Lizard
4
Martwię się o przepełnienie, ale tę metodę można dostosować do BigInts i nadal być znacznie szybszą niż inne metody. W przypadku, gdy ktoś zastanawia się, dlaczego wkładam tyle wysiłku w tak prosty problem, tworzę bibliotekę, która pomaga w rozwiązywaniu problemów z Project Euler.
Bill the Lizard
1
Jeśli zastanawiasz się, czy naprawdę możesz parsować ciąg w liczbę całkowitą, czy długą, musisz także sprawdzić, czy liczba całkowita reprezentująca ciąg rzeczywiście pasuje do tych typów danych.
Jonas K
65

Masz, ale powinieneś tylko złapać NumberFormatException.

Ovidiu Pacurar
źródło
7
Tak, uznanie za złą formę, aby złapać więcej wyjątków niż potrzebujesz.
Chris
Masz rację. NFE jest jedynym, który można rzucić, ale nadal jest to zły nawyk, aby się do niego przyzwyczaić.
Bill the Lizard
Myślę, że NPE może zostać wyrzucony, jeśli dane wejściowe są zerowe, więc twoja metoda powinna prawdopodobnie obsłużyć to jawnie, w dowolny sposób.
Dov Wasserman
@Dov: Masz rację, NPE i NFE powinny zostać wyraźnie złapane.
Bill the Lizard
Ta odpowiedź powinna być prawdziwą odpowiedzią na to pytanie.
Breedly,
40

Zrobił szybki test porównawczy. Wyjątki nie są tak naprawdę kosztowne, chyba że zaczniesz wycofywać wiele metod, a JVM musi wykonać wiele pracy, aby ustawić stos wykonawczy. Pozostając w tej samej metodzie, nie są złymi wykonawcami.

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

Wynik:

ByException: 31

ByRegex: 453 (uwaga: kompilacja wzorca za każdym razem)

ByJonas: 16

Zgadzam się, że rozwiązanie Jonasa K. jest również najbardziej niezawodne. Wygląda na to, że wygrywa :)

CodingWithSpike
źródło
13
Świetny pomysł na porównanie wszystkich trzech. Aby być sprawiedliwym w stosunku do metod Regex i Jonas, powinieneś przetestować ciągi niecałkowite, ponieważ właśnie tam metoda Integer.parseInt naprawdę zwolni.
Bill the Lizard
4
Przepraszamy, ale ten test wyrażenia regularnego nie jest dobry. (1) Nie ma potrzeby, aby regex Check Engine do ^i $po raz drugi, ponieważ w matchescały ciąg musi odpowiadać regex (2), str.matchesza każdym razem będzie musiał stworzyć swój własny Pattern, który jest kosztowny. Ze względu na wydajność powinniśmy utworzyć taki Wzorzec tylko raz poza tą metodą i użyć go wewnątrz. (3) Możemy również utworzyć tylko jeden obiekt Matcher i używać go reset(CharSequence)do przekazywania danych użytkownika i zwracania jego matches()wyniku.
Pshemo,
Więc coś takiego private final Matcher m = Pattern.compile("-?\\d+").matcher(""); private boolean byRegex(String str) { return m.reset(str).matches(); }powinno mieć lepszą wydajność.
Pshemo,
@Pshemo Integer.valueOf („1”) i Integer.valueOf („1”) zgłaszają wyjątek, więc sprawdzanie ^ i $ wydaje się rozsądne.
cquezel
1
@cquezel Tak, ale nie jest wymagane, ponieważ matchesjest dodawane ^i $niejawnie. Spójrz na wynik " 123".matches("\\d+")i "123".matches("\\d+"). Zobaczysz falsei true. falsezostanie zwrócone, ponieważ ciąg zaczyna się od spacji, która uniemożliwia pełne dopasowanie wyrażenia regularnego.
Pshemo
37

Ponieważ istnieje możliwość, że ludzie nadal będą tu odwiedzać i będą stronniczy w stosunku do Regex po testach porównawczych ... Więc dam zaktualizowaną wersję testu porównawczego, ze skompilowaną wersją Regex. To, w przeciwieństwie do poprzednich testów porównawczych, pokazuje, że rozwiązanie Regex ma niezmiennie dobrą wydajność.

Skopiowano z Billa jaszczurki i zaktualizowano do skompilowanej wersji:

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

Wyniki:

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
źródło
1
Czas ByCompiledRegex musi obejmować kompilację wyrażenia regularnego w pomiarze czasu.
Martin Carney,
2
@MartinCarney Zmodyfikowałem go i porównałem kompilację wzorców. Oczywiście mój procesor / JIT jest szybszy, ale jeśli interpoluję go z powrotem, czas kompilacji jest następujący 336.
tedder42
2
dla jasności, 336 (ms) dzieje się, gdy kompilacja wzorca jest wykonywana 100k razy, tak jak wszystkie inne linie. Implikując, że zrobiono to tylko raz, jego czas jest zasadniczo zerowy.
tedder42
Dziękujemy za ustawienie rekordu bezpośrednio na skompilowanych czasach wyrażenia regularnego.
LarsH
Może "^[+-]?\\d+$"byłoby jeszcze lepiej.
Adam
34
org.apache.commons.lang.StringUtils.isNumeric 

chociaż standardowa biblioteka Java naprawdę brakuje takich funkcji narzędziowych

Myślę, że Apache Commons to „must have” dla każdego programisty Java

szkoda, że ​​nie jest jeszcze przeniesiony do Java5

Łukasz Bownik
źródło
1
Jedynym problemem jest przepełnienie: SI nadal daje +1 za wzmiankę o commons-lang :)
javamonkey79
2
Innym problemem są liczby ujemne, ale również +1, ponieważ moim zdaniem takie podejście jest najbliższe dobrym rozwiązaniem.
Sandris
22

Zależy to częściowo od tego, co rozumiesz przez „można przekonwertować na liczbę całkowitą”.

Jeśli masz na myśli „może zostać zamieniony na int w Javie”, to odpowiedź od Jonasa jest dobrym początkiem, ale nie do końca kończy pracę. Na przykład minie 999999999999999999999999999999 Dodałbym normalne wywołanie try / catch z twojego pytania na końcu metody.

Sprawdzanie znak po znaku skutecznie odrzuca przypadki „nie liczba całkowita”, pozostawiając „jest to liczba całkowita, ale Java nie może sobie z tym poradzić” przypadki, które mają zostać przechwycone przez wolniejszą trasę wyjątku. Możesz to zrobić trochę ręcznie, ale byłoby to wiele bardziej skomplikowane.

Jon Skeet
źródło
17

Tylko jeden komentarz na temat regexp. Każdy podany tutaj przykład jest błędny! Jeśli chcesz użyć wyrażenia regularnego, nie zapomnij, że skompilowanie wzorca zajmuje dużo czasu. To:

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

a także to:

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

powoduje kompilację wzorca w każdym wywołaniu metody. Aby używać go poprawnie, wykonaj następujące czynności:

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
źródło
5
Możesz wycisnąć nieco większą wydajność, tworząc wcześniej Matchera i używając metody reset (), aby zastosować go do danych wejściowych.
Alan Moore
13

Istnieje wersja guava:

import com.google.common.primitives.Ints;

Integer intValue = Ints.tryParse(stringValue);

Zwróci null zamiast zgłaszania wyjątku, jeśli nie uda się parsować łańcucha.

abalcerek
źródło
3
Najlepsza odpowiedź IMHO. Używaj dobrze przetestowanych bibliotek zamiast rozwijania własnego rozwiązania. (Zobacz także dyskusję tutaj .)
Olivier Cailloux,
12

Skopiowałem kod z odpowiedzi rally25rs i dodałem kilka testów dla danych niecałkowitych. Wyniki są niezaprzeczalnie na korzyść metody opublikowanej przez Jonasa Klemminga. Wyniki dla metody wyjątku, którą pierwotnie opublikowałem, są całkiem dobre, gdy masz dane całkowite, ale są najgorsze, gdy nie masz, podczas gdy wyniki dla rozwiązania RegEx (założę się, że wiele osób korzysta) były konsekwentnie złe. Zobacz odpowiedź Felipe na skompilowany przykład wyrażenia regularnego, który jest znacznie szybszy.

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

Wyniki:

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 jaszczurka
źródło
6

Jest to krótsze, ale krótsze niekoniecznie lepsze (i nie złapie wartości całkowitych, które są poza zakresem, jak wskazano w komentarzu danatela ):

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

Osobiście, ponieważ implementacja jest wyciskana metodą pomocniczą, a poprawność przewyższa długość, po prostu wybrałbym coś takiego, co masz (bez łapania Exceptionklasy podstawowej zamiast NumberFormatException).

Jonny Buchanan
źródło
1
I może \\ d {1,10} jest, choć nie idealny, lepszy niż \\ d + do łapania
liczb
6

Możesz użyć metody dopasowania klasy ciągów. [0-9] reprezentuje wszystkie wartości, jakie mogą być, + oznacza, że ​​musi mieć co najmniej jeden znak, a * oznacza, że ​​może mieć zero lub więcej znaków.

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
źródło
1
Uwaga: to nie pasuje do „+10” lub „-10”), które normalnie byłyby uwzględnione jako prawidłowe liczby całkowite
Tim Wintle
4

Co powiesz na:

return Pattern.matches("-?\\d+", input);
Kristian
źródło
Co z liczbą całkowitą 9999999999999999999999999999999999?
danatel
Nie zapomnij sprawdzić znaku ujemnego.
Jeremy Ruten,
nie musisz zakotwiczać początku i końca wyrażenia regularnego, aby nie przejść „aaa-1999zzz”?
Tim Howland,
2
Tim, kiedy wywołasz jedną z metod match () (String, Pattern i Matcher mają po jednej), regex musi dopasować całe dane wejściowe, dzięki czemu kotwice stają się zbędne. Aby znaleźć dopasowanie zdefiniowane przez większość innych smaków wyrażeń regularnych, musisz użyć Matcher # find ().
Alan Moore
4

To jest wariant Java 8 odpowiedzi Jonasa Klemminga:

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

Kod testowy:

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

Wyniki kodu testowego:

        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
źródło
3

Wystarczy sprawdzić 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
źródło
3

Jeśli tablica ciągów zawiera czyste liczby całkowite i ciągi, poniższy kod powinien działać. Musisz tylko spojrzeć na pierwszą postać. np. [„4”, „44”, „abc”, „77”, „bond”]

if (Character.isDigit(string.charAt(0))) {
    //Do something with int
}
realPK
źródło
3

Możesz także użyć klasy Scanner i użyć hasNextInt () - a to pozwala na testowanie również innych typów, takich jak zmiennoprzecinkowe itp.

Matthew Schinckel
źródło
Ta odpowiedź dała mi przypomnienie, którego potrzebowałem. Zupełnie zapomniałem, że skaner miał taką funkcję. T-up
Hubro
2

Jeśli chcesz sprawdzić, czy ciąg reprezentuje liczbę całkowitą pasującą do typu int, dokonałem niewielkiej modyfikacji odpowiedzi jonas, aby ciągi reprezentujące liczby całkowite większe niż Integer.MAX_VALUE lub mniejsze niż Integer.MIN_VALUE, teraz zwrócą fałszywe. Na przykład: „3147483647” zwróci fałsz, ponieważ 3147483647 jest większy niż 2147483647, i podobnie „-2147483649” również zwróci fałsz, ponieważ -2147483649 jest mniejszy niż -2147483648.

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

źródło
1
czy możesz edytować swoją odpowiedź i wyjaśnić, w jaki sposób poprawia ona poprzednią odpowiedź, o której wspomniałeś?
Gilles Gouaillardet,
Dzięki za świetną odpowiedź. Ale „123”, tj. 123 wraz ze spacją są uważane za prawidłową liczbę całkowitą.
Saikrishna Radarapu,
1
@ SaikrishnaRadarapu Używają, trim()więc jest to wyraźnie celowy wybór projektu.
Guildenstern
2

Możesz wypróbować narzędzia Apache

NumberUtils.isCreatable(myText)

Zobacz javadoc tutaj

borjab
źródło
1
Wygląda na to, że ta metoda jest przestarzała w najnowszym linku do wydania ). Najwyraźniej powinieneś użyć isCreateable(String)zamiast tego.
Guildenstern
Zaktualizowano Dzięki @Guildenstern
borjab
1

Prawdopodobnie musisz również wziąć pod uwagę przypadek użycia:

Jeśli przez większość czasu spodziewasz się, że liczby będą prawidłowe, wyłapanie wyjątku powoduje jedynie narzut wydajności podczas próby konwersji nieprawidłowych liczb. Natomiast nazywając jakąś isInteger()metodę, a następnie przekonwertować używając Integer.parseInt()będzie zawsze powodować narzut wydajności dla ważnych numerów - struny są analizowane dwa razy, raz przez sprawdzanie i raz przez konwersję.

mobra66
źródło
1

Jest to modyfikacja kodu Jonasa , który sprawdza, czy ciąg znaków znajduje się w zasięgu, aby można go było rzutować na liczbę całkowitą.

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
źródło
1
wygląda dobrze, ale ostatnia pętla for musi mieć reset i do zera (lub 1, jeśli liczba ujemna), ponieważ pętla, która sprawdza, czy każda cyfra jest liczbą, spowoduje, że i będzie długością łańcucha, dlatego ostatnia pętla for nigdy nie ucieknie. Używałbym również stałych Java Integer.MAX_VALUE i Integer.MIN_VALUE zamiast magicznych liczb.
Tim the Enchanter
@TimtheEnchanter Dziękuję za sugestie, całkowicie je przeoczyłem. W mojej edycji, aby je uwzględnić, użyłem nowej zmiennej w pierwszej pętli for, aby uniknąć dodatkowej instrukcji if.
Wayne,
1

Jeśli używasz interfejsu API Androida, możesz użyć:

TextUtils.isDigitsOnly(str);
timxyz
źródło
1

Inna opcja:

private boolean isNumber(String s) {
    boolean isNumber = true;
    for (char c : s.toCharArray()) {
        isNumber = isNumber && Character.isDigit(c);
    }
    return isNumber;
}
Gabriel Kaffka
źródło
0
is_number = true;
try {
  Integer.parseInt(mystr)
} catch (NumberFormatException  e) {
  is_number = false;
}
Ricardo Acras
źródło
5
To robi dokładnie to samo, o co pyta plakat.
Martin Carney,
0

To, co zrobiłeś, działa, ale prawdopodobnie nie zawsze powinieneś to sprawdzać. Wyjątki dotyczące rzucania powinny być zarezerwowane dla „wyjątkowych” sytuacji (może to jednak pasuje do twojego przypadku) i są bardzo kosztowne pod względem wydajności.

Lucas
źródło
Są kosztowne tylko wtedy, gdy zostaną wyrzucone.
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
źródło
0

Działa to tylko dla dodatnich liczb całkowitych.

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
źródło
4
Witamy w Stackoverflow. Przed wskrzeszeniem starego wątku przeczytaj poprzednie odpowiedzi i komentarze. Ta metoda (i możliwe wady) zostały już omówione.
Leigh
0

To działa dla mnie. Wystarczy zidentyfikować, czy Łańcuch jest prymitywny czy liczba.

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
źródło
0

Aby sprawdzić wszystkie znaki int, możesz po prostu użyć podwójnego ujemnego.

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

[^ 0-9] + $ sprawdza, czy są jakieś znaki, które nie są liczbami całkowitymi, więc test nie powiedzie się, jeśli to prawda. Po prostu NIE, a osiągniesz sukces.

Roger F. Gay
źródło
Nie, najwyraźniej tego nie testowałeś. Zwraca to prawdę tylko wtedy, gdy gdzieś w ciągu znajduje się cyfra, a nie, jeśli ciąg jest tylko cyframi. matchesMetoda mecze przeciwko cały ciąg, a nie tylko jego część.
Dawood ibn Kareem
Nie dostaniesz podwójnie negatywnej części.
Roger F. Gay
Cóż, NIE dostaję podwójnego negatywu. To po prostu nie działa. Jeśli masz mieszankę cyfr i liter, trafia to do ifbloku. Nie powinno.
Dawood ibn Kareem
0

Znajdź to może być pomocne:

public static boolean isInteger(String self) {
    try {
        Integer.valueOf(self.trim());
        return true;
    } catch (NumberFormatException nfe) {
        return false;
    }
}
shellbye
źródło
0

Wierzę, że istnieje ryzyko zerowe uruchomiony w drodze wyjątku, bo jak widać poniżej wami bezpiecznie przetwarzać intdo Stringa nie na odwrót.

Więc:

  1. Państwo sprawdzić , czy każdy automat z charakterem w swoich meczów smyczkowych przynajmniej jeden ze znaków { „0”, „1”, „2”, „3”, „4”, „5”, „6”, „7”, „8”, „9”} .

    if(aString.substring(j, j+1).equals(String.valueOf(i)))
  2. Ci Podsumowując wszystkie czasy, że napotkane w gniazdach powyższe znaki.

    digits++;
  3. Na koniec sprawdzasz, czy czasy, w których napotkałeś liczby całkowite jako znaki, są równe długości podanego ciągu.

    if(digits == aString.length())

W praktyce mamy:

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

A wyniki są następujące:

To liczba całkowita !!

To nie jest liczba całkowita !!

Podobnie, można zweryfikować, czy Stringjest floatczy doublejednak w tych przypadkach trzeba spotkać tylko jeden. (kropka) w ciągu znaków i oczywiście sprawdź, czy digits == (aString.length()-1)

Znowu nie ma ryzyka wystąpienia wyjątku parsowania, ale jeśli planujesz parsowanie łańcucha, który jest znany, że zawiera liczbę (powiedzmy int typ danych), musisz najpierw sprawdzić, czy pasuje on do typu danych. W przeciwnym razie musisz go rzucić.

Mam nadzieję, że pomogłem

mark_infinite
źródło