Quelle est la meilleure façon de vérifier si une chaîne représente un entier en Java?


214

J'utilise normalement l'idiome suivant pour vérifier si une chaîne peut être convertie en entier.

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

Est-ce juste moi ou cela semble-t-il un peu hack? Quelle meilleure façon?


Voir ma réponse (avec des repères, basée sur la réponse précédente de CodingWithSpike ) pour voir pourquoi j'ai inversé ma position et accepté la réponse de Jonas Klemming à ce problème. Je pense que ce code original sera utilisé par la plupart des gens car il est plus rapide à implémenter et plus facile à maintenir, mais ses ordres de grandeur sont plus lents lorsque des données non entières sont fournies.


Quelle est votre idée de RegExp pour la solution?
Akshay Pethani, le

Réponses:


171

Si vous n'êtes pas préoccupé par des problèmes de débordement potentiels, cette fonction fonctionnera environ 20 à 30 fois plus rapidement que l'utilisation 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;
}

50
(c <= '/' || c> = ':') est un peu étrange. J'aurais utilisé (c <'0' || c> '9') ... les opérateurs <= et> = sont-ils plus rapides en Java?
Anonyme

3
Pourquoi ne pas utiliser regex? N'est pas renvoyer str.matches ("^ -? \\ d + $") identique au code ci-dessus.
Maglob

15
J'utiliserais cette méthode ou la méthode originale de la question avant l'expression régulière. Ceci pour les performances, la méthode originale pour la vitesse de mise en œuvre et la maintenabilité. La solution regex n'a rien à faire.
Bill the Lizard

4
Je suis préoccupé par le débordement, mais cette méthode peut être adaptée pour BigInts et toujours beaucoup plus rapide que d'autres méthodes. Au cas où quelqu'un se demanderait pourquoi je déploie autant d'efforts dans un problème aussi simple, je crée une bibliothèque pour aider à résoudre les problèmes du projet Euler.
Bill the Lizard

1
Si vous vous demandez si vous pouvez réellement analyser la chaîne dans un entier ou long, vous devrez également vérifier si l'entier que la chaîne représente correspond réellement à ces types de données.
Jonas K

65

Vous l'avez, mais vous ne devriez attraper NumberFormatException.


7
Ouais, c'est considéré comme une mauvaise forme pour attraper plus d'exceptions que nécessaire.
Chris

Vous avez raison. L'ENF est le seul qui peut être lancé, mais c'est toujours une mauvaise habitude à prendre.
Bill the Lizard

Je pense qu'un NPE peut être lancé si l'entrée est nulle, donc votre méthode devrait probablement gérer cela explicitement, quelle que soit la façon dont vous le souhaitez.
Dov Wasserman,

@Dov: Vous avez raison, NPE et NFE devraient tous deux être explicitement capturés.
Bill the Lizard

Cette réponse devrait être la vraie réponse à cette question.
Breedly

40

A fait une référence rapide. Les exceptions ne sont pas vraiment aussi coûteuses, à moins que vous ne commenciez à réapparaître plusieurs méthodes et que la JVM doive faire beaucoup de travail pour mettre la pile d'exécution en place. En restant dans la même méthode, ils ne sont pas mauvais interprètes.

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

Production:

ByException: 31

ByRegex: 453 (remarque: recompiler le modèle à chaque fois)

ByJonas: 16

Je suis d'accord que la solution de Jonas K est également la plus robuste. On dirait qu'il gagne :)


13
Excellente idée de comparer les trois. Pour être juste avec les méthodes Regex et Jonas, vous devez tester avec des chaînes non entières, car c'est là que la méthode Integer.parseInt va vraiment ralentir.
Bill the Lizard

4
Désolé mais ce test d'expression rationnelle n'est pas bon. (1) Vous n'avez pas besoin de faire vérifier le moteur regex pour ^et $deuxième fois puisque dans la matcheschaîne entière doit correspondre regex, (2) à str.matcheschaque fois que devra créer sa propre Patternqui est cher. Pour des raisons de performances, nous ne devons créer ce modèle qu'une seule fois en dehors de cette méthode et l'utiliser à l'intérieur. (3) Nous pouvons également créer un seul objet Matcher et l'utiliser reset(CharSequence)pour transmettre des données utilisateur et renvoyer son matches()résultat.
Pshemo

Donc, quelque chose comme ça private final Matcher m = Pattern.compile("-?\\d+").matcher(""); private boolean byRegex(String str) { return m.reset(str).matches(); }devrait avoir de meilleures performances.
Pshemo

@Pshemo Integer.valueOf ("1") et Integer.valueOf ("1") lèvent tous deux une exception, donc la vérification de ^ et $ semble raisonnable.
cquezel

1
@cquezel Oui, mais ce n'est pas obligatoire car il matchesajoute ^et $implicitement. Jetez un oeil au résultat de " 123".matches("\\d+")et "123".matches("\\d+"). Vous verrez falseet true. falsesera renvoyée car la chaîne commence par un espace qui l'empêche d'être entièrement mise en correspondance par l'expression régulière.
Pshemo

37

Puisqu'il est possible que les gens visitent toujours ici et soient biaisés contre Regex après les benchmarks ... Je vais donc donner une version mise à jour du benchmark, avec une version compilée du Regex. Contrairement aux benchmarks précédents, celui-ci montre que la solution Regex a en fait toujours de bonnes performances.

Copié de Bill the Lizard et mis à jour avec la version compilée:

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

Résultats:

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

1
Le temps ByCompiledRegex doit inclure la compilation du regex dans sa mesure du temps.
Martin Carney

2
@MartinCarney Je l'ai modifié et j'ai compilé la compilation de modèles. Évidemment, mon CPU / JIT est plus rapide, mais si je l'interpole en arrière, le temps de compilation est 336.
tedder42

2
pour être clair, que 336 (ms) est ce qui se passe lorsque la compilation de modèle est effectuée 100 000 fois, comme toutes les autres lignes. Avec l'implication qu'il n'est fait qu'une seule fois, son temps est pratiquement nul.
tedder42

Merci d'avoir mis les pendules à l'heure des regex compilés.
LarsH

Ce "^[+-]?\\d+$"serait peut -être encore mieux.
Adam

34
org.apache.commons.lang.StringUtils.isNumeric 

bien que la bibliothèque standard de Java manque vraiment de telles fonctions utilitaires

Je pense qu'Apache Commons est un "must have" pour tout programmeur Java

dommage qu'il ne soit pas encore porté sur Java5


1
Le seul problème avec cela est le débordement: SI vous donne toujours +1 pour mentionner commons-lang :)
javamonkey79

2
L'autre problème, ce sont les nombres négatifs, mais moi aussi +1, car à mon avis, cette approche est la plus proche d'une bonne solution.
sandris

23

Cela dépend en partie de ce que vous entendez par «peut être converti en entier».

Si vous voulez dire "peut être converti en un entier en Java", la réponse de Jonas est un bon début, mais ne termine pas tout à fait le travail. Il passerait par exemple 999999999999999999999999999999. J'ajouterais l'appel try / catch normal à partir de votre propre question à la fin de la méthode.

Les vérifications caractère par caractère rejetteront efficacement les cas "pas un entier du tout", laissant "c'est un entier mais Java ne peut pas le gérer" les cas pour être capturés par la route d'exception la plus lente. Tu pouvez aussi le faire à la main, mais ce serait beaucoup plus compliqué.


17

Juste un commentaire sur regexp. Chaque exemple fourni ici est faux !. Si vous souhaitez utiliser regexp, n'oubliez pas que la compilation du modèle prend beaucoup de temps. Ce:

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

et aussi ceci:

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

provoque la compilation du modèle dans chaque appel de méthode. Pour l'utiliser correctement, suivez:

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

5
Vous pouvez également obtenir un peu plus de performances en créant à l'avance le Matcher et en utilisant sa méthode reset () pour l'appliquer à l'entrée.
Alan Moore

13

Il existe une version goyave:

import com.google.common.primitives.Ints;

Integer intValue = Ints.tryParse(stringValue);

Il renverra null au lieu de lever une exception s'il ne parvient pas à analyser la chaîne.


3
Meilleure réponse à mon humble avis. Utilisez des bibliothèques bien testées au lieu de déployer votre propre solution. (Voir aussi la discussion ici .)
Olivier Cailloux

12

J'ai copié le code de la réponse rally25rs et ajouté quelques tests pour les données non entières. Les résultats sont indéniablement en faveur de la méthode publiée par Jonas Klemming. Les résultats de la méthode Exception que j'ai publiée à l'origine sont assez bons lorsque vous avez des données entières, mais ils sont les pires lorsque vous n'en avez pas, tandis que les résultats de la solution RegEx (que je parie que beaucoup de gens utilisent) étaient toujours mauvais. Voir la réponse de Felipe pour un exemple regex compilé, qui est beaucoup plus rapide.

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

Résultats:

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

6

C'est plus court, mais plus court n'est pas nécessairement meilleur (et il n'attrapera pas les valeurs entières qui sont hors de portée, comme souligné dans le commentaire de danatel ):

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

Personnellement, étant donné que l'implémentation est éculée dans une méthode d'assistance et que l'exactitude l'emporte sur la longueur, j'irais simplement avec quelque chose comme ce que vous avez (moins attraper la Exceptionclasse de base plutôt que NumberFormatException).


1
Et peut-être que \\ d {1,10} est, bien que pas parfait, meilleur que \\ d + pour attraper des entiers Java
Maglob

6

Vous pouvez utiliser la méthode matches de la classe de chaîne. Le [0-9] représente toutes les valeurs qu'il peut être, le + signifie qu'il doit comporter au moins un caractère et le * signifie qu'il peut comporter zéro ou plusieurs caractères.

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

1
Nb cela ne correspond pas à "+10" ou "-10"), qui seraient normalement inclus comme entiers valides
Tim Wintle

4

Que diriez-vous:

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

Qu'en est-il de l'entier 9999999999999999999999999999999999?
danatel

N'oubliez pas de vérifier le signe négatif.
Jeremy Ruten

n'avez-vous pas besoin d'ancrer le début et la fin de l'expression régulière, vous ne passerez donc pas "aaa-1999zzz"?
Tim Howland,

2
Tim, lorsque vous appelez l'une des méthodes matches () (String, Pattern et Matcher en ont chacune une), l'expression régulière doit correspondre à l'ensemble de l'entrée, ce qui rend les ancres redondantes. Pour trouver une correspondance telle que définie par la plupart des autres saveurs d'expression régulière, vous devez utiliser Matcher # find ().
Alan Moore

4

Il s'agit d'une variante Java 8 de la réponse de 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)));
}

Code de test:

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

Résultats du code de test:

        1231231 true
    -1232312312 true
   +12313123131 true
  qwqe123123211 false
              2 true
  0000000001111 true
                false
           123- false
          ++123 false
         123-23 false
           null false
          +-123 false

3

Vous venez de vérifier 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 
 }  

3

Si votre tableau de chaînes contient des entiers et des chaînes purs, le code ci-dessous devrait fonctionner. Il suffit de regarder le premier caractère. par exemple ["4", "44", "abc", "77", "bond"]

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

3

Vous pouvez également utiliser la classe Scanner et utiliser hasNextInt () - et cela vous permet également de tester d'autres types, comme les flottants, etc.


Cette réponse m'a donné un rappel dont j'avais besoin. J'ai complètement oublié que Scanner avait une telle fonction. T-up
Hubro

2

Si vous voulez vérifier si la chaîne représente un entier qui tient dans un type int, j'ai fait une petite modification à la réponse des jonas, de sorte que les chaînes qui représentent des entiers plus grands que Integer.MAX_VALUE ou plus petits que Integer.MIN_VALUE, vont maintenant retourner faux. Par exemple: "3147483647" renverra false car 3147483647 est plus grand que 2147483647, et de même, "-2147483649" renverra également false car -2147483649 est plus petit que -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;
}

1
pouvez-vous modifier votre réponse et expliquer comment elle améliore la réponse précédente que vous avez mentionnée?
Gilles Gouaillardet

Merci pour la bonne réponse. Mais "123" c'est-à-dire que 123 avec l'espace est considéré comme l'entier valide.
Saikrishna Radarapu

1
@SaikrishnaRadarapu Ils utilisent trim()donc c'est clairement un choix de conception intentionnel.
Guildenstern

2

Vous pouvez essayer des utils apache

NumberUtils.isCreatable(myText)

Voir le javadoc ici


1
Semble que cette méthode est déconseillée dans le dernier lien de version ). Apparemment, vous devriez utiliser à la isCreateable(String)place.
Guildenstern

Actualisé. Merci @Guildenstern
borjab

1

Vous devez probablement également tenir compte du cas d'utilisation:

Si, la plupart du temps, vous vous attendez à ce que les nombres soient valides, la capture de l'exception ne provoque qu'une surcharge de performances lorsque vous tentez de convertir des nombres non valides. Alors que l'appel d'une isInteger()méthode, puis la conversion à l'aide Integer.parseInt()entraînera toujours une surcharge de performances pour les nombres valides - les chaînes sont analysées deux fois, une fois par la vérification et une fois par la conversion.


1

Il s'agit d'une modification du code de Jonas qui vérifie si la chaîne se trouve dans la plage à convertir en entier.

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

1
semble bon, mais la dernière boucle for doit avoir i remis à zéro (ou 1 si un nombre négatif) car la boucle qui vérifie si chaque chiffre est un nombre entraînera i étant la longueur de la chaîne, donc la dernière boucle for ne fonctionnera jamais. J'utiliserais également les constantes Java Integer.MAX_VALUE et Integer.MIN_VALUE au lieu des nombres magiques.
Tim l'Enchanteur

@TimtheEnchanter Merci pour les suggestions, je les ai complètement ignorées. Dans ma modification pour les incorporer, j'ai utilisé une nouvelle variable dans la première boucle for pour éviter l'instruction if supplémentaire.
Wayne

1

Si vous utilisez l'API Android, vous pouvez utiliser:

TextUtils.isDigitsOnly(str);

1

Une autre option:

private boolean isNumber(String s) {
    boolean isNumber = true;
    for (char c : s.toCharArray()) {
        isNumber = isNumber && Character.isDigit(c);
    }
    return isNumber;
}

0
is_number = true;
try {
  Integer.parseInt(mystr)
} catch (NumberFormatException  e) {
  is_number = false;
}

5
Cela fait exactement la même chose que l'affiche.
Martin Carney du

0

Ce que vous avez fait fonctionne, mais vous ne devriez probablement pas toujours vérifier de cette façon. Le lancement d'exceptions doit être réservé aux situations "exceptionnelles" (peut-être que cela vous convient, cependant), et sont très coûteux en termes de performances.


Ils ne coûtent que s'ils sont jetés.
Bill the Lizard

0
Number number;
try {
    number = NumberFormat.getInstance().parse("123");
} catch (ParseException e) {
    //not a number - do recovery.
    e.printStackTrace();
}
//use number

0

Cela ne fonctionnerait que pour les entiers positifs.

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

4
Bienvenue sur stackoverflow. Avant de ressusciter un ancien fil, assurez-vous de lire les réponses et commentaires précédents. Cette méthode (et les éventuels inconvénients) ont déjà été discutés.
Leigh

0

Cela fonctionne pour moi. Identifier simplement si une chaîne est une primitive ou un nombre.

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

0

Pour vérifier tous les caractères int, vous pouvez simplement utiliser un double négatif.

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

[^ 0-9] + $ vérifie s'il y a des caractères qui ne sont pas des nombres entiers, donc le test échoue si c'est vrai. Ce n'est PAS le cas et vous réussissez.


Non, vous n'avez clairement pas testé cela. Cela ne renvoie vrai que s'il y a un chiffre quelque part dans la chaîne, pas si la chaîne n'est que des chiffres. La matchesméthode correspond à la chaîne entière, pas seulement à une partie de celle-ci.
Dawood ibn Kareem

Vous n'obtenez pas la double partie négative.
Roger F. Gay

Eh bien, je n'ai PAS le double négatif. Cela ne fonctionne tout simplement pas. Si vous avez un mélange de chiffres et de lettres, cela va dans le ifbloc. Ça ne devrait pas.
Dawood ibn Kareem

0

Trouvez ceci peut être utile:

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

0

Je crois qu'il ya risque zéro en cours d' exécution dans une exception, parce que vous pouvez voir ci - dessous vous analysez toujours en toute sécurité intàString et non l'inverse.

Alors:

  1. Vous vérifiez si chaque emplacement de caractère de votre chaîne correspond à au moins un des caractères {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} .

    if(aString.substring(j, j+1).equals(String.valueOf(i)))
  2. Vous additionnez toutes les fois que vous avez rencontré dans les emplacements les personnages ci-dessus.

    digits++;
  3. Et enfin, vous vérifiez si le nombre de fois où vous avez rencontré des entiers sous forme de caractères est égal à la longueur de la chaîne donnée.

    if(digits == aString.length())

Et dans la pratique, nous avons:

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

Et les résultats sont:

C'est un entier !!

Ce n'est pas un entier !!

De même, vous pouvez valider si a Stringest un floatou un, doublemais dans ces cas, vous ne devez en rencontrer qu'un. (point) dans la chaîne et bien sûr vérifier si digits == (aString.length()-1)

Encore une fois, il n'y a aucun risque d'exécuter une exception d'analyse ici, mais si vous prévoyez d'analyser une chaîne dont on sait qu'elle contient un nombre (disons le type de données int ), vous devez d'abord vérifier si elle correspond au type de données. Sinon, vous devez le lancer.

J'espère avoir aidé

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.