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).
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).
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:
publicstaticboolean 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:
¿\ 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
@ 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.
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().
publicstaticboolean isNumeric(String str){for(char c : str.toCharArray()){if(!Character.isDigit(c))returnfalse;}returntrue;}
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.
publicstaticboolean isStringNumeric(String str ){DecimalFormatSymbols currentLocaleSymbols =DecimalFormatSymbols.getInstance();char localeMinusSign = currentLocaleSymbols.getMinusSign();if(!Character.isDigit( str.charAt(0))&& str.charAt(0)!= localeMinusSign )returnfalse;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;}returnfalse;}}returntrue;}
¿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.
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.
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.
publicstaticboolean isNumericRegex(String str){if(str ==null)returnfalse;return str.matches("-?\\d+");}publicstaticboolean isNumericArray(String str){if(str ==null)returnfalse;char[] data = str.toCharArray();if(data.length <=0)returnfalse;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.returnfalse;}returntrue;}publicstaticboolean isNumericException(String str){if(str ==null)returnfalse;try{/* int i = */Integer.parseInt(str);}catch(NumberFormatException nfe){returnfalse;}returntrue;}
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 signArray 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]Withnull: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:
publicstaticboolean isNumericArray(String str){if(str ==null)returnfalse;for(char c : str.toCharArray())if(c <'0'|| c >'9')returnfalse;returntrue;
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 ()
¿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
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
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)returnfalse;//To check if string is emptyif(str.charAt(0)=='-')
str = str.replaceFirst("-","");// for handling -ve numbersSystem.out.println(str);
str = str.replaceFirst("\\.","");//to check if it contains more than one decimal pointsif(str.length()==0)returnfalse;// to check if it is empty string after removing -ve sign and decimal pointSystem.out.println(str);return str.replaceAll("[0-9]","").length()==0;}
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.
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
*/publicstaticboolean isParsable(Object parser,String str){Class theClass =(parser instanceofClass?(Class)parser: parser.getClass());boolean staticOnly =(parser == theClass), foundAtLeastOne =false;Method[] methods = theClass.getMethods();// Loop over methodsfor(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);returntrue;// 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 methodcontinue;// Look for other parse methods}}}// No more accessible parse method could be found.if(foundAtLeastOne)returnfalse;elsethrownewRuntimeException(newNoSuchMethodException());}/**
* 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
*/publicstaticboolean willParse(Object parser,String str){try{return isParsable(parser, str);}catch(Throwable exception){returnfalse;}}
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+)?$");publicstaticboolean 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:
caracteristicas:
Elimina los ceros innecesarios ["12.0000000" -> "12"]
Elimina los ceros innecesarios ["12.0580000" -> "12.058"]
Elimina caracteres no numéricos ["12.00sdfsdf00" -> "12"]
Maneja valores de cadena negativos ["-12,020000" -> "-12.02"]
Elimina múltiples puntos ["-12.0.20.000" -> "-12.02"]
Sin bibliotecas adicionales, solo Java estándar
Aqui tienes...
publicclassNumUtils{/**
* Transforms a string to an integer. If no numerical chars returns a String "0".
*
* @param str
* @return retStr
*/staticString 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
*/staticString makeToDouble(String str){Boolean dotWasFound =false;String orgStr = str;String retStr;int firstDotPos =0;Boolean negative =false;//check if str is nullif(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 dotsfor(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 beginingdouble 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;}staticboolean isNumeric(String str){try{double d =Double.parseDouble(str);}catch(NumberFormatException nfe){returnfalse;}returntrue;}}
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;publicclassIsNumeric{publicstaticboolean isNumericOne(String s){return s.matches("-?\\d+(\\.\\d+)?");//match a number with optional '-' and decimal. }publicstaticboolean isNumericTwo(String s){try{Double.parseDouble(s);returntrue;}catch(Exception e){returnfalse;}}publicstaticvoid main(String[] args){String test ="12345.F";long before =newDate().getTime();for(int x=0;x<1000000;++x){//isNumericTwo(test);
isNumericOne(test);}long after =newDate().getTime();System.out.println(after-before);}}
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
publicstaticboolean isDigitsOnly(CharSequence str){finalint len = str.length();for(int i =0; i < len; i++){if(!Character.isDigit(str.charAt(i))){returnfalse;}}returntrue;}
La pregunta dice "numérico" que podría incluir valores no enteros.
rghome
3
// only intpublicstaticboolean isNumber(int num){return(num >=48&& c <=57);// 0 - 9}// is type of number including . - e E publicstaticboolean 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 publicstaticboolean 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;}publicstaticboolean isNumeric(String s){try{Double.parseDouble(s);returntrue;}catch(Exception e){returnfalse;}}
publicstaticboolean 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;}
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 =newRegExp("^-?\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);returntrue;}catch(NumberFormatException e){returnfalse;}}
Uso:
int num;if(parseInteger("23", out num)){// Do something with num.}
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.
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 <= mString 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 lengthString 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");
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.
publicstaticboolean isNumeric(finalString input){//Check for null or blank stringif(input ==null|| input.isBlank())returnfalse;//Retrieve the minus sign and decimal separator characters from the current Localefinal var localeMinusSign =DecimalFormatSymbols.getInstance().getMinusSign();final var localeDecimalSeparator =DecimalFormatSymbols.getInstance().getDecimalSeparator();//Check if first character is a minus signfinal var isNegative = input.charAt(0)== localeMinusSign;//Check if string is not just a minus signif(isNegative && input.length()==1)returnfalse;
var isDecimalSeparatorFound =false;//If the string has a minus sign ignore the first characterfinal 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 separatorfor(var i = startCharIndex; i < input.length(); i++){if(!Character.isDigit(input.charAt(i))){if(input.charAt(i)== localeDecimalSeparator &&!isDecimalSeparatorFound){
isDecimalSeparatorFound =true;}elsereturnfalse;}}returntrue;}
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.
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.
privateboolean isValidStringTrueNumber(String stringNumber){if(stringNumber.isEmpty()){returnfalse;}
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)){returnfalse;}if(!Character.isDigit(charNumber[i]))//Char is not a digit.{if(charNumber[i]==','){if(decimalPointPassed){returnfalse;}
commaFound =true;//check that next three chars are only digits.
commaCounter +=3;}elseif(charNumber[i]=='.'){
decimalPointPassed =true;
countOfDecimalPoint++;}else{returnfalse;}}else//Char is a digit.{if((commaCounter>=0)&&(commaFound)){if(!decimalPointPassed){
commaCounter--;}}if(!commaFound){
countOfDigitsBeforeFirstComma++;}if(!decimalPointPassed){
countOfDigitsBeforeDecimalPoint++;}else{
countOfDigitsAfterDecimalPoint++;}}}if((commaFound)&&(countOfDigitsBeforeFirstComma>3)){returnfalse;}if(countOfDecimalPoint>1){returnfalse;}if((decimalPointPassed)&&((countOfDigitsBeforeDecimalPoint==0)||(countOfDigitsAfterDecimalPoint==0))){returnfalse;}returntrue;}
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.
Integer.parseInt()
no podrán analizar los números móviles conNumberFormatException
.Respuestas:
Con Apache Commons Lang 3.5 y superior:
NumberUtils.isCreatable
oStringUtils.isNumeric
.Con Apache Commons Lang 3.4 y menos:
NumberUtils.isNumber
oStringUtils.isNumeric
.También puede usar
StringUtils.isNumericSpace
que devuelvetrue
cadenas vacías e ignora los espacios internos en la cadena. Otra forma es usar loNumberUtils.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).fuente
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 comprobarloNumberUtils.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:
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:
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:
fuente
.
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:
la documentación se puede encontrar aquí
Mantenlo simple . casi todo el mundo puede "reprogramar" (lo mismo).
fuente
.
,-
Java 8 expresiones lambda.
fuente
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()
.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.
fuente
toCharArray()
crearán una copia de la matriz en el objeto String porque las cadenas son inmutables. Probablemente sea más rápido usar elcharAt(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 comoInteger.parseInt
pero devuelve ennull
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:
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.fuente
No use Excepciones para validar sus valores. Utilice las bibliotecas de utilidades como Apache NumberUtils:
Editar :
Tenga en cuenta que, si su cadena comienza con un 0, NumberUtils interpretará su valor como hexadecimal.
fuente
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.
Los resultados en velocidad que obtuve fueron:
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:
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
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 ()
fuente
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
fuente
true
por un solo más"+"
o menos"-"
, yfalse
por"0."
"0."
es válido paraDouble.parseDouble()
y es un literal válido de acuerdo con JLS ( §3.10.2 )!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:
fuente
""
es un número pero"3.14"
y"-1"
no lo son?Puedes usar
NumberFormat#parse
:fuente
value
.Si usa Java para desarrollar la aplicación de Android, podría usar función TextUtils.isDigitsOnly .
fuente
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 unClass
o unobject
. Esto también le permitirá usar analizadores personalizados que ha escrito y debería funcionar para cualquier escenario, por ejemplo:Aquí está mi código completo con descripciones de métodos.
fuente
Para hacer coincidir solo enteros positivos de base diez, que contienen solo dígitos ASCII, use:
fuente
Un enfoque de buen desempeño que evita el try-catch y maneja números negativos y notación científica.
fuente
Aquí está mi clase para verificar si una cadena es numérica. También corrige cadenas numéricas:
caracteristicas:
Aqui tienes...
fuente
Aquí hay otro ejemplo actualizado de coincidencia de expresiones regulares "CraigTP" con más validaciones.
fuente
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.
fuente
// por favor verifique el siguiente código
fuente
fuente
Este es un ejemplo simple para esta verificación:
fuente
Puede usar el objeto java.util.Scanner.
fuente
Modifiqué la solución de CraigTP para aceptar la notación científica y el punto y la coma también como separadores decimales.
ejemplo
fuente
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.
Uso:
fuente
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.
fuente
Puede usar NumberUtils.isCreatable () de Apache Commons Lang .
Dado que NumberUtils.isNumber quedará en desuso en 4.0, utilice NumberUtils.isCreatable () en su lugar.
fuente
Java 8 Stream, expresión lambda, interfaz funcional
Todos los casos manejados ( cadena nula, cadena vacía, etc. )
fuente
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
Verifique el número de longitud fija (suponga que la longitud es 6)
Verifique el número de longitud variable entre (suponga una longitud de 4 a 6)
Verifique el número decimal de longitud variable entre (suponga una longitud de 4 a 7)
Espero que ayude a muchos.
fuente
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.
fuente
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
Ha cambiado el valor de entrada para que no tenga espacios. Puede eliminar esa línea si lo desea.
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.
fuente