Cómo verificar si una cadena es numérica en Java

887

¿Cómo comprobarías si una cadena era un número antes de analizarla?

Craig Angus
fuente
36
Todas las soluciones propuestas con expresiones regulares no funcionarán para números hexadecimales.
Oscar Castiblanco
y pasar una cadena nula en la función de coincidencias (...) generará una excepción NullPointer
Hitesh Sahu
Vea la respuesta de Max Malysh para una solución concisa de Java 8 sin bibliotecas de terceros.
Andy Thomas
@HiteshSahu cadenas nulas parecen ser manejado con gracia en versión más reciente (incluyendo Java y 6.x 7.x)
lifebalance
Todas las soluciones propuestas para usar Integer.parseInt()no podrán analizar los números móviles con NumberFormatException.
No es un error

Respuestas:

691

Con Apache Commons Lang 3.5 y superior: NumberUtils.isCreatableo StringUtils.isNumeric.

Con Apache Commons Lang 3.4 y menos: NumberUtils.isNumbero StringUtils.isNumeric.

También puede usar StringUtils.isNumericSpaceque devuelve truecadenas vacías e ignora los espacios internos en la cadena. Otra forma es usar lo NumberUtils.isParsableque básicamente verifica que el número se pueda analizar de acuerdo con Java. (Los javadocs vinculados contienen ejemplos detallados para cada método).

palacsint
fuente
59
StringUtils.isNumeric()probablemente no sería apropiado aquí, ya que solo comprueba si la cadena es una secuencia de dígitos. Estaría bien para la mayoría de las entradas, pero no para números con decimales, separadores de grupos, etc.
Jeff Mercado
42
reinventa la rueda porque no incluye una biblioteca completa porque necesita una función de 3 líneas en un solo lugar.
dalvarezmartinez1
12
Sin embargo, ¿realmente vale la pena agregar una biblioteca completa para esta función? Obviamente, si se usa con otras cosas que es genial, pero probablemente sea excesivo teniendo en cuenta que las personas lo han resuelto en una sola línea de código.
Agua
77
No funciona con negativos. Y la mitad de todos los números son negativos, por lo que .....
Paul Draper
66
@PaulDraper: Tienes razón, StringUtilsno es compatible con los signos iniciales, pero debes comprobarlo NumberUtils.isCreatable, es compatible con los negativos correctamente.
palacsint
904

Esto generalmente se realiza con una función simple definida por el usuario (es decir, la función "isNumeric" de Roll-your-own).

Algo como:

public static boolean isNumeric(String str) { 
  try {  
    Double.parseDouble(str);  
    return true;
  } catch(NumberFormatException e){  
    return false;  
  }  
}

Sin embargo, si llama mucho a esta función y espera que muchas de las comprobaciones fallen debido a que no es un número, el rendimiento de este mecanismo no será excelente, ya que depende de las excepciones que se lanzan para cada falla, lo cual es una operación bastante cara.

Un enfoque alternativo puede ser usar una expresión regular para verificar la validez de ser un número:

public static boolean isNumeric(String str) {
  return str.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.
}

Sin embargo, tenga cuidado con el mecanismo RegEx anterior, ya que fallará si está utilizando dígitos no árabes (es decir, números distintos de 0 a 9). Esto se debe a que la parte "\ d" de la RegEx solo coincidirá [0-9] y efectivamente no tiene conocimiento numérico internacional. (¡Gracias a OregonGhost por señalar esto!)

O incluso otra alternativa es usar el objeto java.text.NumberFormat incorporado de Java para ver si, después de analizar la cadena, la posición del analizador está al final de la cadena. Si es así, podemos suponer que toda la cadena es numérica:

public static boolean isNumeric(String str) {
  NumberFormat formatter = NumberFormat.getInstance();
  ParsePosition pos = new ParsePosition(0);
  formatter.parse(str, pos);
  return str.length() == pos.getIndex();
}
CraigTP
fuente
77
¿\ D en Java Regex solo coincide con dígitos latinos? Si es como expresiones regulares .NET, se encontrará con un problema con otros dígitos (por ejemplo, árabe), como se explica aquí: blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
OregonGhost
3
la solución numberFormatter es probablemente solo marginalmente mejor que la captura de NumberFormatException. Sospecho que la mejor manera es usar regex one.
Chii el
11
Tenga .en cuenta que en su expresión regular coincidirá con cualquier carácter, no solo con el separador decimal.
jqno
99
+1 por darse cuenta del gasto de try / catch. Este es realmente un enfoque horrible para usar a largo plazo para uso repetido, pero realmente estamos atrapados con eso en Java.
demongolem
55
Tenga en cuenta que no existen los "números latinos", y los números 0-9 son, de hecho, números arábigos. Las personas probablemente estén familiarizadas con los números romanos, que fueron utilizados por personas que hablaban latín, en la forma I, II, III, IV, V, VI, etc. en.wikipedia.org/wiki/Arabic_numerals ; en.wikipedia.org/wiki/Roman_numerals
dantiston
152

si estás en Android, entonces debes usar:

android.text.TextUtils.isDigitsOnly(CharSequence str)

la documentación se puede encontrar aquí

Mantenlo simple . casi todo el mundo puede "reprogramar" (lo mismo).

Ahmed Alejo
fuente
44
@ kape123 :) seguro "123.456" no contiene dígitos.
Ahmed Alejo
8
Nota: esto da como resultado NPE para la entrada nula. Además, no funciona con números negativos o decimales.
gMale
2
¡¡Me gusta!! Creo que esto es absolutamente para los dígitos. No es para .,-
ilusionJJ
Esto es justo lo que estaba buscando. Algo simple de verificar solo para los dígitos 0-9. Configuré un filtro en la declaración de mi EditText, pero en caso de que se cambie o se reemplace en el futuro, también es bueno tener una verificación programática simple.
jwehrle
127

Java 8 expresiones lambda.

String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
Max Malysh
fuente
44
También puede usar una referencia de método: someString.chars (). AllMatch (Character :: isDigit)
Wienczny
3
Agradable, pero todavía está reinventando la rueda como casi todas las "soluciones" aquí. Además, falla en 'nulo' (como casi todos los demás).
qben
8
Esta respuesta es concisa, simple y legible. Casi puedes leerlo como inglés: "todos los dígitos coinciden". No requiere bibliotecas de terceros. No utiliza excepciones en casos no excepcionales. Esto debería convertirse en la respuesta aceptada.
Andy Thomas
14
¿Qué producirá para "-1"?
Balázs Németh
2
No es la respuesta correcta. Una cadena numérica puede tener caracteres no numéricos (por ejemplo, "." O "-") y aún así ser perfectamente numérica. Por ejemplo, 0.5, -1 y 1,000 fallarán con esta respuesta y, sin embargo, son perfectamente numéricos.
Simeon G
126

Como @CraigTP había mencionado en su excelente respuesta, también tengo preocupaciones de rendimiento similares al usar Excepciones para probar si la cadena es numérica o no. Así que termino dividiendo la cadena y la uso java.lang.Character.isDigit().

public static boolean isNumeric(String str)
{
    for (char c : str.toCharArray())
    {
        if (!Character.isDigit(c)) return false;
    }
    return true;
}

Según el Javadoc , Character.isDigit(char)reconocerá correctamente los dígitos no latinos. En cuanto al rendimiento, creo que un simple N número de comparaciones donde N es el número de caracteres en la cadena sería más eficiente computacionalmente que hacer una coincidencia de expresiones regulares.

ACTUALIZACIÓN: Como señaló Jean-François Corbett en el comentario, el código anterior solo validaría enteros positivos, lo que cubre la mayoría de mi caso de uso. A continuación se muestra el código actualizado que valida correctamente los números decimales de acuerdo con la configuración regional predeterminada utilizada en su sistema, con el supuesto de que el separador decimal solo ocurre una vez en la cadena.

public static boolean isStringNumeric( String str )
{
    DecimalFormatSymbols currentLocaleSymbols = DecimalFormatSymbols.getInstance();
    char localeMinusSign = currentLocaleSymbols.getMinusSign();

    if ( !Character.isDigit( str.charAt( 0 ) ) && str.charAt( 0 ) != localeMinusSign ) return false;

    boolean isDecimalSeparatorFound = false;
    char localeDecimalSeparator = currentLocaleSymbols.getDecimalSeparator();

    for ( char c : str.substring( 1 ).toCharArray() )
    {
        if ( !Character.isDigit( c ) )
        {
            if ( c == localeDecimalSeparator && !isDecimalSeparatorFound )
            {
                isDecimalSeparatorFound = true;
                continue;
            }
            return false;
        }
    }
    return true;
}
Ibrahim Arief
fuente
44
¿El separador decimal tampoco hará que esto falle?
Jean-François Corbett
1
@ Jean-FrançoisCorbett: Buen punto, he actualizado el código con uno más nuevo que acepta separadores decimales.
Ibrahim Arief
2
¿El signo -ve falla en esta función?
java_mouse
3
Las llamadas toCharArray()crearán una copia de la matriz en el objeto String porque las cadenas son inmutables. Probablemente sea más rápido usar el charAt(int index)método directamente en el objeto String.
Mike Kucera
2
Se generará StringIndexOutOfBoundsExceptioncuando se pasa una cadena con longitud 0. Se puede arreglar conif(str.length() == 0) return false;
samgak
43

Guayaba biblioteca de Google proporciona un método de ayuda agradable de hacer esto: Ints.tryParse. Lo usa como Integer.parseIntpero devuelve en nulllugar de lanzar una excepción si la cadena no se analiza a un entero válido. Tenga en cuenta que devuelve Integer, no int, por lo que debe convertirlo / autobox de nuevo a int.

Ejemplo:

String s1 = "22";
String s2 = "22.2";
Integer oInt1 = Ints.tryParse(s1);
Integer oInt2 = Ints.tryParse(s2);

int i1 = -1;
if (oInt1 != null) {
    i1 = oInt1.intValue();
}
int i2 = -1;
if (oInt2 != null) {
    i2 = oInt2.intValue();
}

System.out.println(i1);  // prints 22
System.out.println(i2);  // prints -1

Sin embargo, a partir del lanzamiento actual, Guava r11, todavía está marcado @Beta.

No lo he comparado. Mirando el código fuente, hay una sobrecarga de muchas comprobaciones de cordura, pero al final usan Character.digit(string.charAt(idx)), similar, pero ligeramente diferente de, la respuesta de @Ibrahim anterior. No hay excepción en el manejo de gastos generales bajo las cubiertas en su implementación.

quux00
fuente
Tenga en cuenta que esto arrojaría NPE en caso de que el argumento sea nulo.
Vadzim
30

No use Excepciones para validar sus valores. Utilice las bibliotecas de utilidades como Apache NumberUtils:

NumberUtils.isNumber(myStringValue);

Editar :

Tenga en cuenta que, si su cadena comienza con un 0, NumberUtils interpretará su valor como hexadecimal.

NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
Goot
fuente
77
La respuesta aceptada, tres años antes, ya está cubierta Number.isNumber().
Andy Thomas
No lo creo. Se actualizó o cambió la respuesta aceptada. Recuerdo que la respuesta aceptada no cubrió NumberUtils, por eso agregué mi respuesta. Pero gracias por el comentario
Goot
2
@Goot: el historial de la respuesta aceptada muestra que Number.isNumber()estaba presente desde la primera versión de la respuesta, con fecha del 24 de septiembre de 12 a las 17:01.
Andy Thomas
@Goot, esto es bastante bueno ya que también cubre la verificación del valor decimal, a diferencia de StringUtils.
Heena Hussain
24

¿Por qué todos presionan por soluciones de excepción / expresiones regulares?

Si bien puedo entender que la mayoría de las personas están bien con el uso de try / catch, si quieres hacerlo con frecuencia ... puede ser extremadamente exigente.

Lo que hice aquí fue tomar la expresión regular, los métodos parseNumber () y el método de búsqueda de matriz para ver cuál era el más eficiente. Esta vez, solo miré los números enteros.

public static boolean isNumericRegex(String str) {
    if (str == null)
        return false;
    return str.matches("-?\\d+");
}

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    char[] data = str.toCharArray();
    if (data.length <= 0)
        return false;
    int index = 0;
    if (data[0] == '-' && data.length > 1)
        index = 1;
    for (; index < data.length; index++) {
        if (data[index] < '0' || data[index] > '9') // Character.isDigit() can go here too.
            return false;
    }
    return true;
}

public static boolean isNumericException(String str) {
    if (str == null)
        return false;
    try {  
        /* int i = */ Integer.parseInt(str);
    } catch (NumberFormatException nfe) {  
        return false;  
    }
    return true;
}

Los resultados en velocidad que obtuve fueron:

Done with: for (int i = 0; i < 10000000; i++)...

With only valid numbers ("59815833" and "-59815833"):
    Array numeric took 395.808192 ms [39.5808192 ns each]
    Regex took 2609.262595 ms [260.9262595 ns each]
    Exception numeric took 428.050207 ms [42.8050207 ns each]
    // Negative sign
    Array numeric took 355.788273 ms [35.5788273 ns each]
    Regex took 2746.278466 ms [274.6278466 ns each]
    Exception numeric took 518.989902 ms [51.8989902 ns each]
    // Single value ("1")
    Array numeric took 317.861267 ms [31.7861267 ns each]
    Regex took 2505.313201 ms [250.5313201 ns each]
    Exception numeric took 239.956955 ms [23.9956955 ns each]
    // With Character.isDigit()
    Array numeric took 400.734616 ms [40.0734616 ns each]
    Regex took 2663.052417 ms [266.3052417 ns each]
    Exception numeric took 401.235906 ms [40.1235906 ns each]

With invalid characters ("5981a5833" and "a"):
    Array numeric took 343.205793 ms [34.3205793 ns each]
    Regex took 2608.739933 ms [260.8739933 ns each]
    Exception numeric took 7317.201775 ms [731.7201775 ns each]
    // With a single character ("a")
    Array numeric took 291.695519 ms [29.1695519 ns each]
    Regex took 2287.25378 ms [228.725378 ns each]
    Exception numeric took 7095.969481 ms [709.5969481 ns each]

With null:
    Array numeric took 214.663834 ms [21.4663834 ns each]
    Regex took 201.395992 ms [20.1395992 ns each]
    Exception numeric took 233.049327 ms [23.3049327 ns each]
    Exception numeric took 6603.669427 ms [660.3669427 ns each] if there is no if/null check

Descargo de responsabilidad: no estoy afirmando que estos métodos estén 100% optimizados, son solo para la demostración de los datos

Excepciones ganadas si y solo si el número es de 4 caracteres o menos, y cada cadena siempre es un número ... en cuyo caso, ¿por qué incluso tener un cheque?

En resumen, es extremadamente doloroso si te encuentras con números inválidos con frecuencia con try / catch, lo cual tiene sentido. Una regla importante que siempre sigo es NUNCA use try / catch para el flujo del programa . Este es un ejemplo de por qué.

Curiosamente, el simple if char <0 || > 9 fue extremadamente simple de escribir, fácil de recordar (y debería funcionar en varios idiomas) y gana casi todos los escenarios de prueba.

El único inconveniente es que supongo que Integer.parseInt () podría manejar números que no son ASCII, mientras que el método de búsqueda de matriz no lo hace.


Para aquellos que se preguntan por qué dije que es fácil recordar el conjunto de caracteres uno, si saben que no hay signos negativos, pueden salirse con la suya con algo condensado como este:

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    for (char c : str.toCharArray())
        if (c < '0' || c > '9')
            return false;
    return true;

Por último, como nota final, tenía curiosidad sobre el operador de asignación en el ejemplo aceptado con todos los votos. Agregar en la asignación de

double d = Double.parseDouble(...)

no solo es inútil ya que ni siquiera usa el valor, sino que desperdicia el tiempo de procesamiento y aumenta el tiempo de ejecución en unos pocos nanosegundos (lo que llevó a un aumento de 100-200 ms en las pruebas). No puedo ver por qué alguien haría eso, ya que en realidad es un trabajo adicional para reducir el rendimiento.

Uno pensaría que se optimizaría ... aunque tal vez debería verificar el código de bytes y ver qué está haciendo el compilador. Eso no explica por qué siempre se mostró más largo para mí, aunque de alguna manera está optimizado ... por lo tanto, me pregunto qué está pasando. Como nota: por más largo, me refiero a ejecutar la prueba para 10000000 iteraciones, y ejecutar ese programa varias veces (10x +) siempre demostró que es más lento.

EDITAR: se actualizó una prueba para Character.isDigit ()

Agua
fuente
44
¿No compila esto una nueva expresión regular cada vez? Eso no parece muy eficiente.
Samuel Edwin Ward
1
Esa es la @SamuelEdwinWard toda razón por la que hice este post ... el ejemplo de expresiones regulares usa, siempre que las respuestas de otras personas y mostró cómo es ineficaz. Incluso si intenta regex con precompilación anticipada y solo usando eso, las diferencias de tiempo son: 2587 ms para la regex que publiqué de otras personas proporcionadas, 950 ms cuando se compiló por adelantado, 144 ms cuando lo hice como un matriz numérica (para iteraciones de 1 mil de la misma cadena). Compilar con anticipación obviamente ayudaría, pero lamentablemente sigue siendo bastante inferior a la forma de la matriz ... a menos que haya una optimización increíble que no conozca.
Agua
Creer que Regex hace las cosas más rápido es casi una falacia. Si es una búsqueda única, sí, lo entiendo ... ¡pero he notado que el código escrito de manera eficiente realmente supera la expresión regular lo suficiente como para sorprenderlo! Gran publicación @ Water
Yo Apps
19
public static boolean isNumeric(String str)
{
    return str.matches("-?\\d+(.\\d+)?");
}

La expresión regular de CraigTP (que se muestra arriba) produce algunos falsos positivos. Por ejemplo, "23y4" se contará como un número porque '.' coincide con cualquier carácter que no sea el punto decimal.

También rechazará cualquier número con un '+' inicial

Una alternativa que evita estos dos problemas menores es

public static boolean isNumeric(String str)
{
    return str.matches("[+-]?\\d*(\\.\\d+)?");
}
usuario872985
fuente
esto regresará truepor un solo más "+"o menos "-", y falsepor"0."
user85421
Buena captura en el single más o menos. Es "0" un numero valido?
user872985
"0."es válido para Double.parseDouble()y es un literal válido de acuerdo con JLS ( §3.10.2 )!
user85421
Crear expresiones regulares también es costoso. La expresión regular debe crearse una vez y reutilizarse
Daniel Nuriyev
1
deberías cambiarlo amatches("-?\\d+([.]\\d+)?")
Bobs
14

Podemos intentar reemplazar todos los números de la cadena dada con (""), es decir, un espacio en blanco y si después de eso la longitud de la cadena es cero, entonces podemos decir que la cadena dada contiene solo números. [Si encuentra útil esta respuesta, considere votarla] Ejemplo:

boolean isNumber(String str){
        if(str.length() == 0)
            return false; //To check if string is empty

        if(str.charAt(0) == '-')
            str = str.replaceFirst("-","");// for handling -ve numbers

        System.out.println(str);

        str = str.replaceFirst("\\.",""); //to check if it contains more than one decimal points

        if(str.length() == 0)
            return false; // to check if it is empty string after removing -ve sign and decimal point
        System.out.println(str);

        return str.replaceAll("[0-9]","").length() == 0;
    }
Ketan Ramteke
fuente
Entonces, ¿ ""es un número pero "3.14"y "-1"no lo son?
Eric Duminil
Evidentemente, no se aplica a todas las formas numéricas, pero aquí hay un voto positivo para pensar de manera diferente ... si el pensamiento original era suyo, eso es.
gbenroscience
12

Puedes usar NumberFormat#parse:

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}
Artem Barger
fuente
Ofreció una edición: faltaba .getInstance (). +1 ya que esta fue la respuesta con la que fui al encontrar esta pregunta.
8bitjunkie
55
Costoso si se usa extensivamente
extensivamente Daniel Nuriyev
1
También pasará si hay caracteres basura al final de value.
Brian White
Crearía
1
Esto funcionó para el formato de número 0x0001 donde Double.parseDouble no funcionaba. +1
Lubina77
8

Aquí estaba mi respuesta al problema.

Un cajón de sastre método de conveniencia que se puede utilizar para analizar cualquier cadena con cualquier tipo de programa de análisis: isParsable(Object parser, String str). El analizador puede ser un Classo un object. Esto también le permitirá usar analizadores personalizados que ha escrito y debería funcionar para cualquier escenario, por ejemplo:

isParsable(Integer.class, "11");
isParsable(Double.class, "11.11");
Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");

Aquí está mi código completo con descripciones de métodos.

import java.lang.reflect.*;

/**
 * METHOD: isParsable<p><p>
 * 
 * This method will look through the methods of the specified <code>from</code> parameter
 * looking for a public method name starting with "parse" which has only one String
 * parameter.<p>
 * 
 * The <code>parser</code> parameter can be a class or an instantiated object, eg:
 * <code>Integer.class</code> or <code>new Integer(1)</code>. If you use a
 * <code>Class</code> type then only static methods are considered.<p>
 * 
 * When looping through potential methods, it first looks at the <code>Class</code> associated
 * with the <code>parser</code> parameter, then looks through the methods of the parent's class
 * followed by subsequent ancestors, using the first method that matches the criteria specified
 * above.<p>
 * 
 * This method will hide any normal parse exceptions, but throws any exceptions due to
 * programmatic errors, eg: NullPointerExceptions, etc. If you specify a <code>parser</code>
 * parameter which has no matching parse methods, a NoSuchMethodException will be thrown
 * embedded within a RuntimeException.<p><p>
 * 
 * Example:<br>
 * <code>isParsable(Boolean.class, "true");<br>
 * isParsable(Integer.class, "11");<br>
 * isParsable(Double.class, "11.11");<br>
 * Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");<br>
 * isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");<br></code>
 * <p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @throws java.lang.NoSuchMethodException If no such method is accessible 
 */
public static boolean isParsable(Object parser, String str) {
    Class theClass = (parser instanceof Class? (Class)parser: parser.getClass());
    boolean staticOnly = (parser == theClass), foundAtLeastOne = false;
    Method[] methods = theClass.getMethods();

    // Loop over methods
    for (int index = 0; index < methods.length; index++) {
        Method method = methods[index];

        // If method starts with parse, is public and has one String parameter.
        // If the parser parameter was a Class, then also ensure the method is static. 
        if(method.getName().startsWith("parse") &&
            (!staticOnly || Modifier.isStatic(method.getModifiers())) &&
            Modifier.isPublic(method.getModifiers()) &&
            method.getGenericParameterTypes().length == 1 &&
            method.getGenericParameterTypes()[0] == String.class)
        {
            try {
                foundAtLeastOne = true;
                method.invoke(parser, str);
                return true; // Successfully parsed without exception
            } catch (Exception exception) {
                // If invoke problem, try a different method
                /*if(!(exception instanceof IllegalArgumentException) &&
                   !(exception instanceof IllegalAccessException) &&
                   !(exception instanceof InvocationTargetException))
                        continue; // Look for other parse methods*/

                // Parse method refuses to parse, look for another different method
                continue; // Look for other parse methods
            }
        }
    }

    // No more accessible parse method could be found.
    if(foundAtLeastOne) return false;
    else throw new RuntimeException(new NoSuchMethodException());
}


/**
 * METHOD: willParse<p><p>
 * 
 * A convienence method which calls the isParseable method, but does not throw any exceptions
 * which could be thrown through programatic errors.<p>
 * 
 * Use of {@link #isParseable(Object, String) isParseable} is recommended for use so programatic
 * errors can be caught in development, unless the value of the <code>parser</code> parameter is
 * unpredictable, or normal programtic exceptions should be ignored.<p>
 * 
 * See {@link #isParseable(Object, String) isParseable} for full description of method
 * usability.<p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @see #isParseable(Object, String) for full description of method usability 
 */
public static boolean willParse(Object parser, String str) {
    try {
        return isParsable(parser, str);
    } catch(Throwable exception) {
        return false;
    }
}
Jamie Bell
fuente
5

Para hacer coincidir solo enteros positivos de base diez, que contienen solo dígitos ASCII, use:

public static boolean isNumeric(String maybeNumeric) {
    return maybeNumeric != null && maybeNumeric.matches("[0-9]+");
}
usuario11153
fuente
5

Un enfoque de buen desempeño que evita el try-catch y maneja números negativos y notación científica.

Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );

public static boolean isNumeric( String value ) 
{
    return value != null && PATTERN.matcher( value ).matches();
}
lars
fuente
5

Aquí está mi clase para verificar si una cadena es numérica. También corrige cadenas numéricas:

caracteristicas:

  1. Elimina los ceros innecesarios ["12.0000000" -> "12"]
  2. Elimina los ceros innecesarios ["12.0580000" -> "12.058"]
  3. Elimina caracteres no numéricos ["12.00sdfsdf00" -> "12"]
  4. Maneja valores de cadena negativos ["-12,020000" -> "-12.02"]
  5. Elimina múltiples puntos ["-12.0.20.000" -> "-12.02"]
  6. Sin bibliotecas adicionales, solo Java estándar

Aqui tienes...

public class NumUtils {
    /**
     * Transforms a string to an integer. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToInteger(String str) {
        String s = str;
        double d;
        d = Double.parseDouble(makeToDouble(s));
        int i = (int) (d + 0.5D);
        String retStr = String.valueOf(i);
        System.out.printf(retStr + "   ");
        return retStr;
    }

    /**
     * Transforms a string to an double. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToDouble(String str) {

        Boolean dotWasFound = false;
        String orgStr = str;
        String retStr;
        int firstDotPos = 0;
        Boolean negative = false;

        //check if str is null
        if(str.length()==0){
            str="0";
        }

        //check if first sign is "-"
        if (str.charAt(0) == '-') {
            negative = true;
        }

        //check if str containg any number or else set the string to '0'
        if (!str.matches(".*\\d+.*")) {
            str = "0";
        }

        //Replace ',' with '.'  (for some european users who use the ',' as decimal separator)
        str = str.replaceAll(",", ".");
        str = str.replaceAll("[^\\d.]", "");

        //Removes the any second dots
        for (int i_char = 0; i_char < str.length(); i_char++) {
            if (str.charAt(i_char) == '.') {
                dotWasFound = true;
                firstDotPos = i_char;
                break;
            }
        }
        if (dotWasFound) {
            String befDot = str.substring(0, firstDotPos + 1);
            String aftDot = str.substring(firstDotPos + 1, str.length());
            aftDot = aftDot.replaceAll("\\.", "");
            str = befDot + aftDot;
        }

        //Removes zeros from the begining
        double uglyMethod = Double.parseDouble(str);
        str = String.valueOf(uglyMethod);

        //Removes the .0
        str = str.replaceAll("([0-9])\\.0+([^0-9]|$)", "$1$2");

        retStr = str;

        if (negative) {
            retStr = "-"+retStr;
        }

        return retStr;

    }

    static boolean isNumeric(String str) {
        try {
            double d = Double.parseDouble(str);
        } catch (NumberFormatException nfe) {
            return false;
        }
        return true;
    }

}
Albóndiga
fuente
5

Regex Matching

Aquí hay otro ejemplo actualizado de coincidencia de expresiones regulares "CraigTP" con más validaciones.

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  1. Solo se -permite un signo negativo y debe estar al principio.
  2. Después del signo negativo debe haber un dígito.
  3. Solo se .permite un signo decimal .
  4. Después del signo decimal debe haber un dígito.

Prueba de expresiones regulares

1                  --                   **VALID**
1.                 --                   INVALID
1..                --                   INVALID
1.1                --                   **VALID**
1.1.1              --                   INVALID

-1                 --                   **VALID**
--1                --                   INVALID
-1.                --                   INVALID
-1.1               --                   **VALID**
-1.1.1             --                   INVALID
Madan Sapkota
fuente
5

Las excepciones son caras, pero en este caso el RegEx lleva mucho más tiempo. El siguiente código muestra una prueba simple de dos funciones: una con excepciones y otra con expresiones regulares. En mi máquina, la versión RegEx es 10 veces más lenta que la excepción.

import java.util.Date;


public class IsNumeric {

public static boolean isNumericOne(String s) {
    return s.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.      
}

public static boolean isNumericTwo(String s) {
    try {
        Double.parseDouble(s);
        return true;
    } catch (Exception e) {
        return false;
    }
}

public static void main(String [] args) {

    String test = "12345.F";

    long before = new Date().getTime();     
    for(int x=0;x<1000000;++x) {
        //isNumericTwo(test);
        isNumericOne(test);
    }
    long after = new Date().getTime();

    System.out.println(after-before);

}

}
ChrisCantrell
fuente
En general, creo que este tipo de código se usaría para verificar cosas como la entrada escrita. En ese caso, la velocidad no es una consideración y hacer algo tan feo como lanzar una excepción para verificar si un número o no es incorrecto.
user872985
Tal vez no. La entrada mecanografiada generalmente es verificada por el componente UI donde los errores pueden mostrarse inmediatamente antes de enviar el valor. Puede ser más común validar cadenas de archivos de texto de entrada grandes, donde el rendimiento es importante. El objetivo en mi respuesta aquí es abordar la declaración "las excepciones son lentas" en la respuesta aceptada. La expresión regular compleja es mucho más costosa. Y no hay ningún "lanzamiento feo" en mi código, solo una forma más rápida de detectar violaciones. Con un enfoque de verificar primero y luego calcular, realiza dos pases a través de la entrada: uno para verificar y luego otro para convertir.
ChrisCantrell
5

// por favor verifique el siguiente código

public static boolean isDigitsOnly(CharSequence str) {
    final int len = str.length();
    for (int i = 0; i < len; i++) {
        if (!Character.isDigit(str.charAt(i))) {
            return false;
        }
    }
    return true;
}
Tejas Parmar
fuente
La pregunta dice "numérico" que podría incluir valores no enteros.
rghome
3
// only int
public static boolean isNumber(int num) 
{
    return (num >= 48 && c <= 57); // 0 - 9
}

// is type of number including . - e E 
public static boolean isNumber(String s) 
{
    boolean isNumber = true;
    for(int i = 0; i < s.length() && isNumber; i++) 
    {
        char c = s.charAt(i);
        isNumber = isNumber & (
            (c >= '0' && c <= '9') || (c == '.') || (c == 'e') || (c == 'E') || (c == '')
        );
    }
    return isInteger;
}

// is type of number 
public static boolean isInteger(String s) 
{
    boolean isInteger = true;
    for(int i = 0; i < s.length() && isInteger; i++) 
    {
        char c = s.charAt(i);
        isInteger = isInteger & ((c >= '0' && c <= '9'));
    }
    return isInteger;
}

public static boolean isNumeric(String s) 
{
    try
    {
        Double.parseDouble(s);
        return true;
    }
    catch (Exception e) 
    {
        return false;
    }
}
Elye M.
fuente
3

Este es un ejemplo simple para esta verificación:

public static boolean isNumericString(String input) {
    boolean result = false;

    if(input != null && input.length() > 0) {
        char[] charArray = input.toCharArray();

        for(char c : charArray) {
            if(c >= '0' && c <= '9') {
                // it is a digit
                result = true;
            } else {
                result = false;
                break;
            }
        }
    }

    return result;
}
ARIJIT
fuente
3

Puede usar el objeto java.util.Scanner.

public static boolean isNumeric(String inputData) {
      Scanner sc = new Scanner(inputData);
      return sc.hasNextInt();
    }
Yu Wai Hlaing
fuente
2

Modifiqué la solución de CraigTP para aceptar la notación científica y el punto y la coma también como separadores decimales.

^-?\d+([,\.]\d+)?([eE]-?\d+)?$

ejemplo

var re = new RegExp("^-?\d+([,\.]\d+)?([eE]-?\d+)?$");
re.test("-6546"); // true
re.test("-6546355e-4456"); // true
re.test("-6546.355e-4456"); // true, though debatable
re.test("-6546.35.5e-4456"); // false
re.test("-6546.35.5e-4456.6"); // false
AndyTheEntity
fuente
2

Es por eso que me gusta el enfoque Try * en .NET. Además del método Parse tradicional que es como el de Java, también tiene un método TryParse. No soy bueno en la sintaxis de Java (¿fuera de los parámetros?), Así que trate lo siguiente como algún tipo de pseudocódigo. Sin embargo, debería aclarar el concepto.

boolean parseInteger(String s, out int number)
{
    try {
        number = Integer.parseInt(myString);
        return true;
    } catch(NumberFormatException e) {
        return false;
    }
}

Uso:

int num;
if (parseInteger("23", out num)) {
    // Do something with num.
}
OregonGhost
fuente
sí, no hay "parámetros de salida" en Java y dado que el contenedor Integer es inmutable (por lo tanto, no se puede usar como una referencia válida para almacenar la salida), la opción idiomática sensata sería devolver un objeto Integer que podría ser nulo si el análisis ha fallado. Una opción más fea podría ser pasar un int [1] como parámetro de salida.
fortran
Sí, recuerdo una discusión sobre por qué Java no tiene parámetros de salida. pero supongo que devolver un número entero (como nulo, si es necesario) también estaría bien, aunque no sé sobre el rendimiento de Java con respecto al boxing / unboxing.
OregonGhost
44
Me gusta C # tanto como el siguiente, pero no sirve de nada agregar un fragmento de código .NET C # para una pregunta de Java cuando las características no existen en Java
Shane
Crearía
2

Analizarlo (es decir, con Integer#parseInt ) y simplemente captura la excepción. =)

Para aclarar: la función parseInt comprueba si puede analizar el número en cualquier caso (obviamente) y si desea analizarlo de todos modos, no tendrá ningún impacto en el rendimiento al realizar el análisis.

Si no desea analizarlo (o analizarlo muy, muy raramente), es posible que desee hacerlo de manera diferente, por supuesto.

gha.st
fuente
1
Costoso si se usa
extensivamente
Crearía
Double.parseDouble
Alex78191
2

Puede usar NumberUtils.isCreatable () de Apache Commons Lang .

Dado que NumberUtils.isNumber quedará en desuso en 4.0, utilice NumberUtils.isCreatable () en su lugar.

Cenxui
fuente
2

Java 8 Stream, expresión lambda, interfaz funcional

Todos los casos manejados ( cadena nula, cadena vacía, etc. )

String someString = null; // something="", something="123abc", something="123123"

boolean isNumeric = Stream.of(someString)
            .filter(s -> s != null && !s.isEmpty())
            .filter(Pattern.compile("\\D").asPredicate().negate())
            .mapToLong(Long::valueOf)
            .boxed()
            .findAny()
            .isPresent();
Noor Nawaz
fuente
2

He ilustrado algunas condiciones para verificar números y decimales sin usar ninguna API,

Comprobar longitud de corrección Número de 1 dígito

Character.isDigit(char)

Verifique el número de longitud fija (suponga que la longitud es 6)

String number = "132452";
if(number.matches("([0-9]{6})"))
System.out.println("6 digits number identified");

Verifique el número de longitud variable entre (suponga una longitud de 4 a 6)

//  {n,m}  n <= length <= m
String number = "132452";
if(number.matches("([0-9]{4,6})"))
System.out.println("Number Identified between 4 to 6 length");

String number = "132";
if(!number.matches("([0-9]{4,6})"))
System.out.println("Number not in length range or different format");

Verifique el número decimal de longitud variable entre (suponga una longitud de 4 a 7)

//  It will not count the '.' (Period) in length
String decimal = "132.45";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1.12";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1234";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "-10.123";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "123..4";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "132";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "1.1";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

Espero que ayude a muchos.

ArifMustafa
fuente
2

Basado en otras respuestas, escribí la mía y no utiliza patrones ni análisis con comprobación de excepciones.

Comprueba un máximo de un signo menos y comprueba un máximo de un punto decimal.

Aquí hay algunos ejemplos y sus resultados:

"1", "-1", "-1.5" y "-1.556" devuelven verdadero

"1..5", "1A.5", "1.5D", "-" y "--1" devuelven falso

Nota: Si es necesario, puede modificar esto para aceptar un parámetro de configuración regional y pasarlo a las llamadas DecimalFormatSymbols.getInstance () para usar una configuración regional específica en lugar de la actual.

 public static boolean isNumeric(final String input) {
    //Check for null or blank string
    if(input == null || input.isBlank()) return false;

    //Retrieve the minus sign and decimal separator characters from the current Locale
    final var localeMinusSign = DecimalFormatSymbols.getInstance().getMinusSign();
    final var localeDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();

    //Check if first character is a minus sign
    final var isNegative = input.charAt(0) == localeMinusSign;
    //Check if string is not just a minus sign
    if (isNegative && input.length() == 1) return false;

    var isDecimalSeparatorFound = false;

    //If the string has a minus sign ignore the first character
    final var startCharIndex = isNegative ? 1 : 0;

    //Check if each character is a number or a decimal separator
    //and make sure string only has a maximum of one decimal separator
    for (var i = startCharIndex; i < input.length(); i++) {
        if(!Character.isDigit(input.charAt(i))) {
            if(input.charAt(i) == localeDecimalSeparator && !isDecimalSeparatorFound) {
                isDecimalSeparatorFound = true;
            } else return false;
        }
    }
    return true;
}
Josh Gager
fuente
1

Aquí hay dos métodos que podrían funcionar. (Sin usar excepciones). Nota: Java es un valor de paso por defecto y el valor de una cadena es la dirección de los datos del objeto de la cadena. Entonces, cuando estás haciendo

stringNumber = stringNumber.replaceAll(" ", "");

Ha cambiado el valor de entrada para que no tenga espacios. Puede eliminar esa línea si lo desea.

private boolean isValidStringNumber(String stringNumber)
{
    if(stringNumber.isEmpty())
    {
        return false;
    }

    stringNumber = stringNumber.replaceAll(" ", "");

    char [] charNumber = stringNumber.toCharArray();
    for(int i =0 ; i<charNumber.length ;i++)
    {
        if(!Character.isDigit(charNumber[i]))
        {
            return false;
        }
    }
    return true;
}

Aquí hay otro método en caso de que desee permitir flotantes. Este método supuestamente permite que los números en el formulario pasen 1,123,123,123,123,123.123. Lo acabo de hacer y creo que necesita más pruebas para asegurarse de que funciona.

private boolean isValidStringTrueNumber(String stringNumber)
{
    if(stringNumber.isEmpty())
    {
        return false;
    }

    stringNumber = stringNumber.replaceAll(" ", "");
    int countOfDecimalPoint = 0;
    boolean decimalPointPassed = false;
    boolean commaFound = false;
    int countOfDigitsBeforeDecimalPoint = 0;
    int countOfDigitsAfterDecimalPoint =0 ;
    int commaCounter=0;
    int countOfDigitsBeforeFirstComma = 0;

    char [] charNumber = stringNumber.toCharArray();
    for(int i =0 ; i<charNumber.length ;i++)
    {
        if((commaCounter>3)||(commaCounter<0))
        {
            return false;
        }
        if(!Character.isDigit(charNumber[i]))//Char is not a digit.
        {
            if(charNumber[i]==',')
            {
                if(decimalPointPassed)
                {
                    return false;
                }
                commaFound = true;
                //check that next three chars are only digits.
                commaCounter +=3;
            }
            else if(charNumber[i]=='.')
            {
                decimalPointPassed = true;
                countOfDecimalPoint++;
            }
            else
            {
                return false;
            }
        }
        else //Char is a digit.
        {
            if ((commaCounter>=0)&&(commaFound))
            {
                if(!decimalPointPassed)
                {
                    commaCounter--;
                }
            }

            if(!commaFound)
            {
                countOfDigitsBeforeFirstComma++;
            }

            if(!decimalPointPassed)
            {
                countOfDigitsBeforeDecimalPoint++;
            }
            else
            {
                countOfDigitsAfterDecimalPoint++;
            }
        }
    }
    if((commaFound)&&(countOfDigitsBeforeFirstComma>3))
    {
        return false;
    }
    if(countOfDecimalPoint>1)
    {
        return false;
    }

    if((decimalPointPassed)&&((countOfDigitsBeforeDecimalPoint==0)||(countOfDigitsAfterDecimalPoint==0)))
    {
        return false;
    }
    return true;
}
XForCE07
fuente
Oh, buena pregunta Supongo que este solo funciona con enteros de tipo normal. El método se creó inicialmente para filtrar los números de teléfono de entrada y contar los números.
XForCE07