Quel est le meilleur moyen de vérifier si une chaîne représente un entier en Java?

StackOverflow https://stackoverflow.com/questions/237159

  •  04-07-2019
  •  | 
  •  

Question

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

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

Est-ce juste moi, ou est-ce que cela semble un peu ridicule? Quel est le meilleur moyen?

Voir ma réponse (avec des points de repère, basé sur la réponse précédente par CodingWithSpike ) pour comprendre pourquoi j’ai inversé ma position et accepté les réponses 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 à maintenir, mais il est beaucoup plus lent lorsque les données non entières sont fournies.

Était-ce utile?

La solution

Si vous n’êtes pas préoccupé par les éventuels problèmes de débordement, cette fonction sera environ 20 à 30 fois plus rapide que l’utilisation de 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;
}

Autres conseils

Vous l'avez, mais vous ne devez capturer que NumberFormatException .

Puisqu'il est possible que les gens visitent encore ici et qu'ils soient biaisés contre Regex après les points de repère ... Je vais donc vous donner une version mise à jour du point de repère, avec une version compilée de Regex. Ce qui, contrairement aux précédents, montre que la solution Regex a toujours de bonnes performances.

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

private final Pattern pattern = Pattern.compile("^-?\\d+
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
quot;); 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+<*>quot;); } 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:

<*>

Fait un repère rapide. Les exceptions ne coûtent en réalité pas très cher, sauf si vous commencez à récupérer plusieurs méthodes et que la machine virtuelle Java doit effectuer beaucoup de travail pour mettre en place la pile d'exécution. En restant dans la même méthode, ils ne sont pas mauvais.

 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+<*>quot;);
 }

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

Sortie:

  

ByException: 31

     

ByRegex: 453 (note: recompiler le motif à chaque fois)

     

ByJonas: 16

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

org.apache.commons.lang.StringUtils.isNumeric 

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

Je pense qu’Apache Commons est un "doit avoir". pour chaque programmeur Java

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

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

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

La vérification caractère par caractère rejettera efficacement "pas un entier du tout". cas, en laissant "c’est un entier, mais Java ne peut pas le gérer" les cas à intercepter par la route d'exception plus lente. Vous pourriez faire cela aussi à la main, mais ce serait beaucoup plus compliqué.

Juste un commentaire à propos de regexp. Tous les exemples fournis ici sont faux! Si vous voulez utiliser regexp, n'oubliez pas que la compilation du motif prend beaucoup de temps. Ceci:

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

et aussi ceci:

import java.util.regex.Pattern;

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

    boolean isNaturalNumber(CharSequence input) {
        return input != null && PATTERN.matcher(input).matches();
    }
}

provoque la compilation du motif dans chaque appel de méthode. Pour l’utiliser correctement, suivez:

<*>

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 initialement publiés sont plutôt bons lorsque vous avez des données entières, mais ils sont les pires lorsque vous ne les avez pas, tandis que les résultats de la solution RegEx (que je parie que beaucoup de gens utilisent) étaient systématiquement mauvais. Voir la réponse de Felipe pour un exemple d'expression régulière 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+
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
quot;); } 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:

<*>

Il existe une version de goyave:

import com.google.common.primitives.Ints;

Integer intValue = Ints.tryParse(stringValue);

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

C'est plus court, mais plus court n'est pas nécessairement meilleur (et il ne capture pas les valeurs entières qui sont hors limites, comme indiqué dans le commentaire de danatel ):

input.matches("^-?\\d+<*>quot;);

Personnellement, étant donné que l'implémentation est gâchée par une méthode d'assistance et que la correction l'emporte sur la longueur, je voudrais simplement utiliser quelque chose comme ce que vous avez (moins la classe de base Exception plutôt que NumberFormatException ).

Vous pouvez utiliser la méthode des correspondances de la classe string. Le [0-9] représente toutes les valeurs possibles, le + signifie qu'il doit comporter au moins un caractère et le *, qu'il peut contenir zéro caractère ou plus.

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

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

Si votre tableau String 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
}

Vous pouvez également utiliser le Scanner class, et utilisez hasNextInt () - et cela vous permet de tester d'autres types, tels que les flottants, etc.

Que diriez-vous de:

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

Vous venez de vérifier ExceptionDeFormatFormat : -

 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 
 }  

Vous pouvez essayer Apache Utils

NumberUtils.isNumber( myText)

Voir le javadoc ici

Vous devez probablement prendre en compte le cas d'utilisation également:

Si la plupart du temps, vous vous attendez à ce que les chiffres soient valides, le fait de capturer l'exception ne fait qu'engendrer une surcharge de performances lorsque vous tentez de convertir des nombres non valides. Considérant que l'appel d'une méthode isInteger () , puis la conversion à l'aide de Integer.parseInt () entraînera toujours une surcharge de performances pour les nombres valides - les chaînes sont analysé deux fois, une fois par le chèque et une fois par la conversion.

Il s'agit d'une modification du code Jonas qui vérifie si la chaîne est dans la plage pour pouvoir être convertie en un 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;
}

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

TextUtils.isDigitsOnly(str);

Une autre option:

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

Si vous voulez vérifier si la chaîne représente un entier qui correspond à un type int, j'ai légèrement modifié la réponse des jonas afin que les chaînes représentant des entiers supérieurs à Integer.MAX_VALUE ou inférieures à Integer.MIN_VALUE, retournera maintenant faux. Par exemple: "3147483647" retournera false car 3147483647 est plus grand que 2147483647, et de même, "-2147483649" retournera également false car -2147483649 est inférieur à -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;
}
is_number = true;
try {
  Integer.parseInt(mystr)
} catch (NumberFormatException  e) {
  is_number = false;
}

Ce que vous avez fait fonctionne, mais vous ne devriez probablement pas toujours vérifier cela. Les exceptions de lancer doivent être réservées à "exceptionnel". situations (peut-être que cela convient à votre cas, cependant), et sont très coûteux en termes de performances.

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

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

Cela fonctionne pour moi. Identifiez 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;
    }

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

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

[^ 0-9] + $ vérifie s'il existe des caractères non entiers. Par conséquent, le test échoue s'il est vrai. Ne faites pas ça et vous devenez vrai en cas de succès.

Trouvez ceci peut être utile:

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

Je crois qu'il n'y a aucun risque de rencontrer une exception, car comme vous pouvez le voir ci-dessous, vous analysez toujours en toute sécurité int en String et non l'inverse.

Donc:

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

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

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

    if(digits == aString.length())
    

Et en 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 les suivants:

  

C'est un entier !!

     

Ce n'est pas un entier !!

De même, vous pouvez valider si un String est un float ou un double , mais dans ce cas, vous ne devez rencontrer que . un. (point) dans la chaîne et bien sûr, vérifiez si digits == (aString.length () - 1)

  

Encore une fois, il n'y a aucun risque de rencontrer une exception d'analyse ici, mais si vous prévoyez d'analyser une chaîne connue contenant un nombre (type de données int ), vous devez d'abord vérifier si ça rentre dans le type de données. Sinon, vous devez le lancer.

J'espère avoir aidé

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top