¿Cuál es la mejor manera de verificar si una cadena representa un número entero en Java?

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

  •  04-07-2019
  •  | 
  •  

Pregunta

Normalmente uso el siguiente idioma para verificar si una cadena se puede convertir en un entero.

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

¿Soy solo yo, o esto parece un poco pirateado? ¿Qué es una mejor manera?


Ver mi respuesta (con puntos de referencia, basados ??en la respuesta anterior por CodingWithSpike ) para ver por qué cambié mi posición y acepté la respuesta de Jonas Klemming a este problema. Creo que la mayoría de la gente usará este código original porque es más rápido de implementar y más fácil de mantener, pero es mucho más lento cuando se proporcionan datos no enteros.

¿Fue útil?

Solución

Si no está preocupado por los posibles problemas de desbordamiento, esta función se realizará entre 20 y 30 veces más rápido que con 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;
}

Otros consejos

Lo tienes, pero solo debes capturar NumberFormatException .

Dado que existe la posibilidad de que la gente siga visitando aquí y se sesgue en contra de Regex después de los puntos de referencia ... Así que voy a dar una versión actualizada del punto de referencia, con una versión compilada de Regex. A diferencia de los puntos de referencia anteriores, este muestra que la solución Regex tiene un buen rendimiento constante.

Copiado de Bill the Lizard y actualizado con la versión compilada:

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

Resultados:

<*>

Hizo un punto de referencia rápido. Las excepciones no son realmente tan costosas, a menos que comience a recuperar múltiples métodos y la JVM tiene que hacer un montón de trabajo para poner la pila de ejecución en su lugar. Cuando se mantienen en el mismo método, no tienen un mal desempeño.

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

Salida:

  

ByException: 31

     

ByRegex: 453 (nota: volver a compilar el patrón cada vez)

     

ByJonas: 16

Estoy de acuerdo en que la solución de Jonas K también es la más robusta. Parece que gana :)

org.apache.commons.lang.StringUtils.isNumeric 

aunque la biblioteca estándar de Java realmente pierde tales funciones de utilidad

Creo que Apache Commons es un " debe tener " para todos los programadores de Java

Lástima que aún no se haya portado a Java5

Depende en parte de lo que quieras decir con " se puede convertir en un número entero " ;.

Si quiere decir que " se puede convertir en un int en Java " Entonces la respuesta de Jonas es un buen comienzo, pero no termina el trabajo. Pasaría 9999999999999999999999999999999999 por ejemplo. Yo agregaría la llamada normal de prueba / captura de su propia pregunta al final del método.

Las comprobaciones de carácter por carácter rechazarán de manera eficiente " no un entero en absoluto " los casos, dejando " es un número entero pero Java no puede manejarlo " Casos a ser capturados por la ruta de excepción más lenta. Usted podría hacer esto poco a mano también, pero sería un lote más complicado.

Sólo un comentario sobre regexp. Todos los ejemplos proporcionados aquí son incorrectos. Si desea utilizar regexp, no olvide que compilar el patrón lleva mucho tiempo. Esto:

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

y también esto:

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

provoca la compilación del patrón en cada llamada de método. Para usarlo correctamente sigue:

<*>

Copié el código de la respuesta de rally25rs y agregué algunas pruebas para datos no enteros. Los resultados son innegablemente a favor del método publicado por Jonas Klemming. Los resultados para el método de Excepción que publiqué originalmente son bastante buenos cuando tienes datos enteros, pero son los peores cuando no los tienes, mientras que los resultados para la solución RegEx (que apuesto a que mucha gente usa) fueron consistentemente malos. Consulte la la respuesta de Felipe para obtener un ejemplo de expresión regular compilado, que es mucho más rápido.

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

Resultados:

<*>

Hay versión de guayaba:

import com.google.common.primitives.Ints;

Integer intValue = Ints.tryParse(stringValue);

Devolverá un valor nulo en lugar de lanzar una excepción si no puede analizar la cadena.

Esto es más corto, pero más corto no es necesariamente mejor (y no detectará valores enteros que estén fuera de rango, como se señala en el comentario de danatel ):

input.matches("^-?\\d+<*>quot;);
Personalmente, ya que la implementación se retira en un método de ayuda y la corrección triunfa sobre la longitud, solo me quedaría con algo como lo que tienes (menos la captura de la clase de Exception en lugar de la NumberFormatException ).

Puedes usar el método de coincidencias de la clase de cadena. El [0-9] representa todos los valores que puede ser, el + significa que debe tener al menos un carácter de longitud, y el * significa que puede tener cero o más caracteres de longitud.

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

Esta es una variación de Java 8 de la respuesta 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)));
}

Código de prueba:

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

Resultados del código de prueba:

        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 la matriz de cadenas contiene enteros y cadenas puros, el código a continuación debería funcionar. Solo hay que mirar el primer personaje. p.ej. [" 4 ", " 44 ", " abc ", " 77 ", " bond "]

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

También puede usar el Escáner clase, y use hasNextInt () - y esto le permite probar otros tipos, como flotadores, etc.

Cómo sobre: ??

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

Simplemente marca 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 
 }  

Puedes probar apache utils

NumberUtils.isNumber( myText)

Consulte javadoc aquí

Es probable que también deba tomar en cuenta el caso de uso:

Si la mayoría de las veces espera que los números sean válidos, la captura de la excepción solo provoca una sobrecarga de rendimiento al intentar convertir números no válidos. Mientras que llamar a algún método isInteger () y luego convertir utilizando Integer.parseInt () , siempre causará una sobrecarga de rendimiento para los números válidos; las cadenas son analizado dos veces, una vez por el cheque y una vez por la conversión.

Esta es una modificación del código de Jonas que comprueba si la cadena está dentro del rango para convertirla en un entero.

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 está utilizando la API de Android, puede usar:

TextUtils.isDigitsOnly(str);

Otra opción:

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

Si desea verificar si la cadena representa un número entero que se ajusta a un tipo int, hice una pequeña modificación en la respuesta de jonas, de modo que las cadenas que representan números enteros más grandes que Integer.MAX_VALUE o más pequeñas que Integer.MIN_VALUE, Ahora devolverá falso. Por ejemplo: " 3147483647 " devolverá false porque 3147483647 es más grande que 2147483647, y de la misma manera, " -2147483649 " también devolverá false porque -2147483649 es más pequeño 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;
}
is_number = true;
try {
  Integer.parseInt(mystr)
} catch (NumberFormatException  e) {
  is_number = false;
}

Lo que hiciste funciona, pero probablemente no siempre deberías verificarlo. Las excepciones de lanzamiento deben reservarse para " excepcional " situaciones (tal vez eso encaja en su caso, sin embargo), y son muy costosas en términos de rendimiento.

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

Esto funcionaría solo para enteros positivos.

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

Esto funciona para mí. Simplemente para identificar si una Cadena es una primitiva o un número.

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

Para verificar todos los caracteres int, simplemente puede usar un doble negativo.

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

[^ 0-9] + $ verifica si hay algún carácter que no sea entero, por lo que la prueba falla si es verdadera. Simplemente NO eso y se hace realidad en el éxito.

Encuentra esto puede ser útil:

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

Creo que hay un riesgo cero en una excepción, porque como puede ver a continuación, siempre analiza de forma segura int a String y no al revés.

Entonces:

  1. Usted verifica si cada espacio de caracteres en su cadena coincide al menos uno de los caracteres {" 0 ", " 1 ", " 2 ", 3 ", " 4 ", " ;, " ;, " ;, 6 "; 8 ", " 9 "} .

    if(aString.substring(j, j+1).equals(String.valueOf(i)))
    
  2. Usted suma todas las veces que encontró en las ranuras las anteriores personajes.

    digits++;
    
  3. Y finalmente, verifica si las veces que encontraste los enteros como los caracteres son iguales a la longitud de la cadena dada.

    if(digits == aString.length())
    

Y en la práctica tenemos:

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

Y los resultados son:

  

¡Es un número entero!

     

¡No es un número entero!

Del mismo modo, puede validar si un String es un float o un double pero en esos casos solo tiene que encontrar uno. (punto) en la Cadena y, por supuesto, compruebe si digit == (aString.length () - 1)

  

Nuevamente, aquí no hay riesgo de que se ejecute una excepción de análisis, pero si planea analizar una cadena que se sabe que contiene un número (digamos int tipo de datos), primero debe verificar si encaja en el tipo de datos. De lo contrario, debes lanzarlo.

Espero haberte ayudado

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top