¿Cómo comprobarías si una cadena era un número antes de analizarla?
Integer.parseInt()
no podrán analizar los números móviles con NumberFormatException
.
¿Cómo comprobarías si una cadena era un número antes de analizarla?
Integer.parseInt()
no podrán analizar los números móviles con NumberFormatException
.
Respuestas:
Con Apache Commons Lang 3.5 y superior: NumberUtils.isCreatable
o StringUtils.isNumeric
.
Con Apache Commons Lang 3.4 y menos: NumberUtils.isNumber
o StringUtils.isNumeric
.
También puede usar StringUtils.isNumericSpace
que devuelve true
cadenas vacías e ignora los espacios internos en la cadena. Otra forma es usar lo NumberUtils.isParsable
que básicamente verifica que el número se pueda analizar de acuerdo con Java. (Los javadocs vinculados contienen ejemplos detallados para cada método).
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.
StringUtils
no es compatible con los signos iniciales, pero debes comprobarlo NumberUtils.isCreatable
, es compatible con los negativos correctamente.
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();
}
.
en cuenta que en su expresión regular coincidirá con cualquier carácter, no solo con el separador decimal.
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).
.
,-
Java 8 expresiones lambda.
String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
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;
}
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.
StringIndexOutOfBoundsException
cuando se pasa una cadena con longitud 0. Se puede arreglar conif(str.length() == 0) return false;
Guayaba biblioteca de Google proporciona un método de ayuda agradable de hacer esto: Ints.tryParse
. Lo usa como Integer.parseInt
pero devuelve en null
lugar 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.
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
Number.isNumber()
.
Number.isNumber()
estaba presente desde la primera versión de la respuesta, con fecha del 24 de septiembre de 12 a las 17:01.
¿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 ()
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+)?");
}
true
por un solo más "+"
o menos "-"
, y false
por"0."
matches("-?\\d+([.]\\d+)?")
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;
}
""
es un número pero "3.14"
y "-1"
no lo son?
Puedes usar NumberFormat#parse
:
try
{
NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
// Not a number.
}
value
.
Si usa Java para desarrollar la aplicación de Android, podría usar función TextUtils.isDigitsOnly .
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 Class
o 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;
}
}
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]+");
}
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();
}
Aquí está mi clase para verificar si una cadena es numérica. También corrige cadenas numéricas:
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;
}
}
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+)?)$");
}
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
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);
}
}
// 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;
}
// 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;
}
}
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;
}
Puede usar el objeto java.util.Scanner.
public static boolean isNumeric(String inputData) {
Scanner sc = new Scanner(inputData);
return sc.hasNextInt();
}
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
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.
}
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.
Puede usar NumberUtils.isCreatable () de Apache Commons Lang .
Dado que NumberUtils.isNumber quedará en desuso en 4.0, utilice NumberUtils.isCreatable () en su lugar.
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();
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.
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;
}
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;
}