tipos - ¿Cuál es la mejor manera de comprobar si una cadena representa un número entero en Java?
tipos de variables en java ejemplos (30)
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 Exception que publiqué originalmente son bastante buenos cuando tienes datos enteros, pero son los peores cuando no lo haces, mientras que los resultados para la solución RegEx (que apostaría que mucha gente usa) fueron consistentemente malos Vea la respuesta de Felipe para 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+$");
}
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:
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
Normalmente utilizo la siguiente expresión idiomática para verificar si una Cadena se puede convertir a un número 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 hackish? ¿Cuál es una mejor manera?
Vea mi respuesta (con puntos de referencia, basados en la respuesta anterior de CodingWithSpike ) para ver por qué he invertido mi posición y acepté la respuesta de Jonas Klemming a este problema. Creo que este código original será utilizado por la mayoría de las personas porque es más rápido de implementar y más fácil de mantener, pero sus órdenes de magnitud son más lentos cuando se proporcionan datos no enteros.
Creo que no hay ningún riesgo de caer en una excepción, porque como puede ver a continuación, siempre se analiza de forma segura int
a String
y no al revés.
Asi que:
Verifica si cada ranura del carácter de la cadena coincide al menos con uno de los caracteres {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} .
if(aString.substring(j, j+1).equals(String.valueOf(i)))
Sumas todas las veces que encontraste en las máquinas tragamonedas los personajes anteriores.
digits++;
Y finalmente, comprueba si los tiempos que encontró enteros como 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!
De manera similar, puede validar si una 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 los digits == (aString.length()-1)
Nuevamente, no hay riesgo de que se ejecute una excepción de análisis aquí, pero si planea analizar una cadena de la que se sabe que contiene un número (digamos tipo de datos int ) primero debe verificar si se ajusta al tipo de datos. De lo contrario, debes lanzarlo.
Espero haber ayudado
Dado que existe la posibilidad de que la gente aún visite aquí y sea parcial en contra de Regex después de los puntos de referencia ... Así que voy a dar una versión actualizada del índice de referencia, con una versión compilada del Regex. Que opuesto a los puntos de referencia anteriores, este muestra que la solución Regex en realidad tiene un buen desempeño constante.
Copiado de Bill the Lizard y actualizado con la versión compilada:
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;
}
Resultados:
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
En parte, depende de lo que quiere decir con "se puede convertir en un número entero".
Si quiere decir "se puede convertir en int en Java", la respuesta de Jonas es un buen comienzo, pero no termina el trabajo. Pasaría 99999999999999999999999999999 por ejemplo. Agregaría la llamada try / catch normal de su propia pregunta al final del método.
Las comprobaciones carácter por carácter rechazarán eficazmente los casos "no un entero en absoluto", dejando que los casos "es un entero pero Java no pueda manejarlo" atrapado por la ruta de excepción más lenta. Podrías hacer esto también a mano, pero sería mucho más complicado.
Encuentre esto puede ser útil:
public static boolean isInteger(String self) {
try {
Integer.valueOf(self.trim());
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
Esta es una modificación del código de Jonas que verifica si la cadena está dentro del rango para convertirse 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;
}
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
Esto es más corto, pero más corto no es necesariamente mejor (y no capturará valores enteros que están fuera de rango, como se señala en el comentario de danatel ):
input.matches("^-?//d+$");
Personalmente, dado que la implementación está escondida en un método de ayuda y la corrección supera la longitud, simplemente elegiría algo como lo que tienes (menos la clase base de Exception
lugar de NumberFormatException
).
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;
}
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;
}
Hay versión de guayaba
import com.google.common.primitives.Ints;
Integer intValue = Ints.tryParse(stringValue);
Devolverá nulo en lugar de lanzar una excepción si no analiza la cadena.
Hice un punto de referencia rápido. Las excepciones no son tan costosas, a menos que empiece a mostrar múltiples métodos y la JVM tiene que trabajar mucho para obtener la pila de ejecución en su lugar. Al permanecer en el mismo método, no son malos artistas.
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;
}
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 es la más robusta también. Parece que él gana :)
Lo que hiciste funciona, pero probablemente no siempre deberías comprobarlo de esa manera. Las excepciones lanzadas deben reservarse para situaciones "excepcionales" (quizás eso se ajuste a su caso) y son muy costosas en términos de rendimiento.
Lo tienes, pero solo debes atrapar NumberFormatException
.
Otra opción:
private boolean isNumber(String s) {
boolean isNumber = true;
for (char c : s.toCharArray()) {
isNumber = isNumber && Character.isDigit(c);
}
return isNumber;
}
Para verificar todos los caracteres internos, simplemente puede usar un doble negativo.
if (! searchString.matches ("[^ 0-9] + $")) ...
[^ 0-9] + $ comprueba si hay caracteres que no son enteros, por lo que la prueba falla si es verdadera. Simplemente NO eso y te haces verdadero con el éxito.
Probablemente también deba tener 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 está provocando una sobrecarga de rendimiento al intentar convertir números no válidos. Mientras que llamar a algún método isInteger()
y luego convertir usando Integer.parseInt()
siempre causará una sobrecarga de rendimiento para los números válidos: las cadenas se analizan dos veces, una vez por el cheque y una por la conversión.
Puede usar el método de coincidencias de la clase de cadena. El [0-9] representa todos los valores que puede tener, el + significa que debe tener al menos un carácter de largo, 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
Qué tal si:
return Pattern.matches("-?//d+", input);
Si desea comprobar si la cadena representa un entero que se ajusta en un tipo int, hice una pequeña modificación en la respuesta de jonas, de modo que las cadenas que representan enteros mayores que Integer.MAX_VALUE o menores que Integer.MIN_VALUE, ahora regresarán falso. Por ejemplo: "3147483647" devolverá falso porque 3147483647 es más grande que 2147483647, y del mismo modo, "-2147483649" también devolverá falso porque -2147483649 es menor 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;
}
Si está utilizando la API de Android, puede usar:
TextUtils.isDigitsOnly(str);
Si no le preocupan los posibles problemas de desbordamiento, esta función funcionará unas 20-30 veces más rápido que el uso 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;
}
Si su matriz de cadenas contiene números enteros puros y cadenas, el siguiente código debería funcionar. Solo tienes que mirar al primer personaje. por ejemplo ["4", "44", "abc", "77", "bond"]
if (Character.isDigit(string.charAt(0))) {
//Do something with int
}
Solo un comentario sobre regexp. ¡Cada ejemplo proporcionado aquí es incorrecto! Si desea usar regexp, no olvide que la compilación del patrón lleva mucho tiempo. Esta:
str.matches("^-?//d+$")
y también esto:
Pattern.matches("-?//d+", input);
causa la compilación del patrón en cada llamada a un método. Para usarlo correctamente, sigue:
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();
}
}
También puede usar la clase de Scanner y usar hasNextInt() - y esto le permite probar otros tipos, también, como flotadores, etc.
Usted acaba de marcar 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
}
Number number;
try {
number = NumberFormat.getInstance().parse("123");
} catch (ParseException e) {
//not a number - do recovery.
e.printStackTrace();
}
//use number
is_number = true;
try {
Integer.parseInt(mystr)
} catch (NumberFormatException e) {
is_number = false;
}
org.apache.commons.lang.StringUtils.isNumeric
aunque la lib del estándar de Java echa de menos tales funciones de utilidad
Creo que Apache Commons es un "must have" para cada programador de Java
Lástima que no está portado a Java5 todavía