Você também pode usar StringUtils.isNumericSpacequais retornostrue para cadeias vazias e ignora os espaços internos na cadeia. Outra maneira é usar o NumberUtils.isParsableque basicamente verifica se o número é analisável de acordo com o Java. (Os javadocs vinculados contêm exemplos detalhados para cada método.)
StringUtils.isNumeric()provavelmente não seria apropriado aqui, pois apenas verifica se a sequência é uma sequência de dígitos. Seria bom para a maioria ints mas não para números com decimais, separadores de grupos, etc
Jeff Mercado
42
reinvente a roda porque você não inclui uma biblioteca inteira porque precisa de uma função de 3 linhas em um só lugar.
precisa saber é o seguinte
12
Vale a pena adicionar uma biblioteca inteira para esse recurso? Obviamente, se for usado com outras coisas, isso é ótimo, mas provavelmente é um exagero, considerando que as pessoas resolveram isso em uma linha de código.
Água
7
Não funciona com negativos. E metade de todos os números são negativos, então .....
Paul Draper
6
@PaulDraper: Você está certo, StringUtilsnão suporta sinais principais, mas deve verificar NumberUtils.isCreatable, ele suporta os negativos corretamente.
Palacsint
904
Isso geralmente é feito com uma função simples definida pelo usuário (ou seja, role a sua própria função "isNumeric").
No entanto, se você estiver chamando muito essa função e espera que muitas das verificações falhem por não ser um número, o desempenho desse mecanismo não será ótimo, pois você conta com exceções lançadas para cada falha, que é uma operação bastante cara.
Uma abordagem alternativa pode ser usar uma expressão regular para verificar a validade de ser um número:
publicstaticboolean isNumeric(String str){return str.matches("-?\\d+(\\.\\d+)?");//match a number with optional '-' and decimal.}
Porém, tenha cuidado com o mecanismo RegEx acima, pois ele falhará se você estiver usando dígitos não árabes (ou seja, números diferentes de 0 a 9). Isso ocorre porque a parte "\ d" do RegEx corresponderá apenas a [0-9] e, efetivamente, não possui reconhecimento internacional de números. (Obrigado ao OregonGhost por apontar isso!)
Ou ainda outra alternativa é usar o objeto java.text.NumberFormat interno do Java para verificar se, após analisar a sequência de caracteres, a posição do analisador está no final da sequência. Se for, podemos assumir que a string inteira é numérica:
\ D no Java Regex corresponde apenas a dígitos latinos? Se for como regexes do .NET, você encontrará um problema com outros dígitos (por exemplo, árabe), conforme explicado aqui: blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
OregonGhost
3
a solução numberFormatter provavelmente é apenas marginalmente melhor do que pegar a NumberFormatException. Eu suspeito que a melhor maneira é usar um regex.
217 Chii
11
Observe que o .em seu regex corresponderá a qualquer caractere, não apenas ao caractere separador decimal.
jqno
9
+1 para realizar a despesa de tentativa / captura. Essa é realmente uma abordagem horrível para uso a longo prazo para uso repetido, mas na verdade estamos presos a isso em Java.
Demongolem 06/09
5
Observe que não existem "números latinos", e os números de 0 a 9 são de fato números arábicos. As pessoas provavelmente conhecem bem os algarismos romanos, que eram usados por pessoas que falavam latim, na forma I, II, III, IV, V, VI, etc. en.wikipedia.org/wiki/Arabic_numerals ; en.wikipedia.org/wiki/Roman_numerals
@ kape123 :) certeza de que "123.456" não contém dígitos.
Ahmed Alejo
8
Nota: isso resulta em NPE para entrada nula. Além disso, não funciona com números negativos ou decimais.
precisa
2
Eu gosto disso!! Eu acho que isso é absolutamente para dígitos. Não para .,-
illusionJJ
Isto é exatamente o que eu estava procurando. Algo simples de verificar apenas os dígitos de 0 a 9. Defino um filtro na declaração do meu EditText, mas, caso as alterações sejam alteradas ou substituídas, é bom ter uma verificação programática simples também.
Você pode usar uma referência de método, também: someString.chars () allMatch (Personagem :: isDigit).
Wienczny
3
Bom, mas ainda está reinventando a roda como quase todas as "soluções" aqui. Além disso, falha em 'null' (como quase todos os outros).
qben
8
Esta resposta é concisa, simples e legível. Você quase pode lê-lo como inglês - "caracteres todos os dígitos correspondentes". Não requer bibliotecas de terceiros. Ele não usa exceções em casos não excepcionais. Essa deve se tornar a resposta aceita.
Andy Thomas
14
O que produzirá para "-1"?
Balázs Németh
2
Não é a resposta certa. Uma sequência numérica pode ter caracteres não numéricos (ex. "." Ou "-") e ainda assim ser perfeitamente numérica. Por exemplo, 0,5, -1 e 1.000 falharão com esta resposta e, no entanto, são perfeitamente numéricos.
Simeon G
126
Como o @CraigTP mencionou em sua excelente resposta, também tenho preocupações semelhantes com o desempenho de usar Exceções para testar se a sequência é numérica ou não. Então, acabo dividindo a corda e o uso java.lang.Character.isDigit().
publicstaticboolean isNumeric(String str){for(char c : str.toCharArray()){if(!Character.isDigit(c))returnfalse;}returntrue;}
De acordo com o Javadoc ,Character.isDigit(char) reconhecerá corretamente dígitos não latinos. Em termos de desempenho, acho que um número N simples de comparações em que N é o número de caracteres na string seria mais eficiente em termos computacionais do que fazer uma correspondência de expressões regulares.
ATUALIZAÇÃO: Conforme apontado por Jean-François Corbett no comentário, o código acima apenas validaria números inteiros positivos, o que cobre a maior parte do meu caso de uso. Abaixo está o código atualizado que valida corretamente os números decimais de acordo com o código do idioma padrão usado em seu sistema, com a suposição de que o separador decimal ocorre apenas uma vez na sequência.
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;}
O separador decimal também não fará com que isso falhe?
Jean-François Corbett
1
@ Jean-FrançoisCorbett: Bom ponto, atualizei o código com um código mais novo que aceita separadores decimais.
Ibrahim Arief
2
O sinal -ve falha nessa função?
Java_mouse 29/05
3
A chamada toCharArray()criará uma cópia da matriz no objeto String porque Strings são imutáveis. Provavelmente mais rápido para usar o charAt(int index)método diretamente no objeto String.
Mike Kucera
2
Irá gerar StringIndexOutOfBoundsExceptionquando passada uma string com comprimento 0. pode ser corrigido comif(str.length() == 0) return false;
samgak
43
Biblioteca Goiaba do Google fornece um método auxiliar bom para fazer isso: Ints.tryParse. Você o usa como ele, Integer.parseIntmas retorna, em nullvez de lançar uma exceção, se a string não analisar um número inteiro válido. Observe que ele retorna Inteiro, não int, então você precisa convertê-lo / autobox novamente em int.
No entanto, a partir da versão atual - Guava r11 - ainda está marcada @Beta.
Eu não fiz benchmarking. Olhando para o código-fonte, existem algumas sobrecargas resultantes de muitas verificações de sanidade, mas no final elas usam Character.digit(string.charAt(idx)), semelhante, mas um pouco diferente da resposta de @Ibrahim acima. Não há exceções no tratamento de sobrecarga sob as coberturas em sua implementação.
A resposta aceita, três anos antes, já estava coberta Number.isNumber().
Andy Thomas
Acho que não. Foi atualizado ou op mudou a resposta aceita. Lembro que a resposta aceita não cobria o NumberUtils e foi por isso que adicionei minha resposta. Mas obrigado pelo comentário
Goot
2
@Goot - O histórico da resposta aceita mostra que Number.isNumber()estava presente na primeira versão da resposta, de 24 de setembro de 12 às 17:01.
Andy Thomas
@ Boot, isso é muito bom, pois também abrange a verificação do valor decimal, ao contrário do StringUtils.
Heena Hussain 02/02
24
Por que todos estão pressionando por soluções de exceção / regex?
Embora eu possa entender que a maioria das pessoas está bem em usar try / catch, se você quiser fazer isso com frequência ... pode ser extremamente desgastante.
O que fiz aqui foi pegar o regex, os métodos parseNumber () e o método de pesquisa de matriz para ver qual era o mais eficiente. Desta vez, eu olhei apenas para números inteiros.
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;}
Os resultados na velocidade que obtive foram:
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
Isenção de responsabilidade: não estou afirmando que esses métodos estão 100% otimizados, são apenas para demonstração dos dados
Exceções ganhas se e somente se o número tiver 4 caracteres ou menos, e cada string for sempre um número ... nesse caso, por que um cheque?
Em resumo, é extremamente doloroso se você encontrar números inválidos frequentemente com o try / catch, o que faz sentido. Uma regra importante que eu sempre sigo é NUNCA usar try / catch para o fluxo do programa . Este é um exemplo do porquê.
Curiosamente, o simples se char <0 || > 9 foi extremamente simples de escrever, fácil de lembrar (e deve funcionar em vários idiomas) e vence quase todos os cenários de teste.
A única desvantagem é que eu acho que Integer.parseInt () pode lidar com números não ASCII, enquanto o método de pesquisa de matriz não.
Para aqueles que se perguntam por que eu disse que é fácil lembrar a matriz de caracteres, se você sabe que não há sinais negativos, pode facilmente se safar com 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 fim, como nota final, fiquei curioso sobre o operador de atribuição no exemplo aceito com todos os votos. Adicionando na atribuição de
double d =Double.parseDouble(...)
não é apenas inútil, pois você nem usa o valor, mas perde tempo de processamento e aumenta o tempo de execução em alguns nanossegundos (o que leva a um aumento de 100-200 ms nos testes). Não vejo por que alguém faria isso, pois na verdade é um trabalho extra para reduzir o desempenho.
Você pensaria que isso seria otimizado ... embora talvez eu deva verificar o bytecode e ver o que o compilador está fazendo. Isso não explica por que sempre apareceu como mais longo para mim, mas se de alguma forma é otimizado ... portanto, eu me pergunto o que está acontecendo. Como observação: por mais tempo, quero dizer executar o teste para 10000000 iterações e executar esse programa várias vezes (10x +) sempre mostrou que era mais lento.
EDIT: Atualizado um teste para Character.isDigit ()
Isso não compila uma nova expressão regular toda vez? Isso não parece muito eficiente.
Samuel Edwin Ward
1
@SamuelEdwinWard Isso é a toda razão pela qual eu fiz este post ... o exemplo regex usado fornecidas respostas de outras pessoas e mostrou quão ineficiente é. Mesmo se você tentar regex pré-compilando com antecedência e usando apenas isso, as diferenças de tempo são: 2587 ms para o regex que eu publiquei de outras pessoas fornecidas, 950 ms quando compilados com antecedência, 144 ms ao fazê-lo como um matriz numérica (para 1 mil iterações da mesma sequência). A compilação antecipada obviamente ajudaria, mas infelizmente ainda é bastante inferior à maneira do array ... a menos que haja alguma otimização insana que eu não conheça.
Water
Acreditar que Regex agiliza as coisas é quase uma falácia. Se é uma pesquisa única, sim, entendi ... mas notei que o código escrito eficientemente supera o regex o suficiente para chocar você! Ótimo post @Water
A expressão regular do CraigTP (mostrada acima) produz alguns falsos positivos. Por exemplo, "23y4" será contado como um número porque '.' corresponde a qualquer caractere que não seja o ponto decimal.
Também rejeitará qualquer número com um '+' inicial
Uma alternativa que evita esses dois pequenos problemas é
isso retornará truepara uma única mais "+"ou menos "-", e falsepara"0."
user85421
Boa captura no single mais ou menos. É "0" um número válido?
user872985
"0."é válido Double.parseDouble()e é um literal válido de acordo com o JLS ( §3.10.2 )!
user85421
Criar expressões regulares também é caro. A expressão regular deve ser criada uma vez e reutilizados
Daniel Nuriyev
1
você deve alterá-lo paramatches("-?\\d+([.]\\d+)?")
Bobs
14
Podemos tentar substituir todos os números da string fornecida por (""), ou seja, espaço em branco e, se depois disso, o comprimento da string for zero, podemos dizer que a string fornecida contém apenas números. [Se você achou esta resposta útil, por favor considere votar] Exemplo:
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;}
Evidentemente não se aplica a todas as formas numéricas, mas aqui está um voto positivo por pensar de forma diferente ... se o pensamento original era seu, isso é.
Um método catch all convenient que você pode usar para analisar qualquer String com qualquer tipo de analisador: isParsable(Object parser, String str) . O analisador pode ser um Classou um object. Isso também permite que você use analisadores personalizados que você escreveu e deve funcionar para qualquer cenário, por exemplo:
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");
Aqui está o meu código completo com descrições 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;}}
Uma abordagem de bom desempenho, evitando tentativa de captura e manipulação de números negativos e notação científica.
Pattern PATTERN =Pattern.compile("^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$");publicstaticboolean isNumeric(String value ){return value !=null&& PATTERN.matcher( value ).matches();}
Remove caracteres não numéricos ["12.00sdfsdf00" -> "12"]
Manipula valores negativos de seqüência de caracteres ["-12,020000" -> "-12,02"]
Remove vários pontos ["-12.0.20.000" -> "-12.02"]
Sem bibliotecas extras, apenas Java padrão
Aqui está...
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;}}
As exceções são caras, mas, neste caso, o RegEx leva muito mais tempo. O código abaixo mostra um teste simples de duas funções - uma usando exceções e outra usando regex. Na minha máquina, a versão RegEx é 10 vezes mais lenta que a exceção.
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);}}
Geralmente, acho que esse tipo de código seria usado para verificar coisas como entrada digitada. Nesse caso, a velocidade não é uma consideração e fazer algo tão feio quanto lançar uma exceção para verificar se há número ou não número está errado.
user872985
Talvez não. A entrada digitada geralmente é verificada pelo componente da interface do usuário, onde os erros podem ser imediatamente mostrados antes de enviar o valor. Pode ser mais comum validar cadeias de arquivos grandes de texto de entrada - onde o desempenho é importante. O objetivo da minha resposta aqui é abordar a declaração "as exceções são lentas" na resposta aceita. Regex complexo é muito mais caro. E não há nenhuma "jogada feia" no meu código - apenas uma maneira mais rápida de detectar violações. Com uma abordagem de verificar primeiro e depois calcular, você faz duas passagens pela entrada: uma para verificar e outra para converter.
ChrisCantrell
5
// verifique o código abaixo
publicstaticboolean isDigitsOnly(CharSequence str){finalint len = str.length();for(int i =0; i < len; i++){if(!Character.isDigit(str.charAt(i))){returnfalse;}}returntrue;}
A pergunta diz "numérico", que pode incluir valores não inteiros.
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;}
Modifiquei a solução do CraigTP para aceitar notação científica e pontos e vírgulas como separadores decimais.
^-?\d+([,\.]\d+)?([eE]-?\d+)?$
exemplo
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
É por isso que eu gosto da abordagem Try * no .NET. Além do método tradicional Parse, que é como o método Java, você também tem um método TryParse. Não sou bom em sintaxe Java (fora de parâmetros?), Portanto, trate o seguinte como algum tipo de pseudo-código. Deve deixar o conceito claro.
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.}
sim, não há "parâmetros de saída" em Java e, como o wrapper Integer é imutável (portanto, não pode ser usado como uma referência válida para armazenar a saída), a opção idiomática sensata seria retornar um objeto Integer que poderia ser nulo se a análise falhou. Uma opção mais feia pode ser passar um int [1] como parâmetro de saída.
fortran
Sim, lembro-me de uma discussão sobre por que Java não possui parâmetros de saída. mas devolver um número inteiro (como nulo, se necessário) também seria bom, acho, embora eu não conheça o desempenho do Java em relação ao boxe / unboxing.
OregonGhost 9/07/2009
4
I como C #, tanto quanto o próximo cara, mas a sua não utilização adicionando um .NET C # trecho de código para uma pergunta Java quando os recursos não existem no Java
Shane
Isso criaria um problema de sonar se você não registrar a exceção
jmhostalet
2
Analise-o (ou seja, com Integer#parseInt) e simplesmente pegue a exceção. =)
Para esclarecer: A função parseInt verifica se é possível analisar o número em qualquer caso (obviamente) e se você deseja analisá-lo de qualquer maneira, não será atingido nenhum desempenho ao realizar a análise.
Se você não deseja analisá-lo (ou analisá-lo muito, muito raramente), convém fazê-lo de maneira diferente, é claro.
Ilustrei algumas condições para verificar números e decimais sem usar nenhuma API,
Verifique o comprimento do número fixo de 1 dígito
Character.isDigit(char)
Verificar número do comprimento fixo (suponha que o comprimento seja 6)
String number ="132452";if(number.matches("([0-9]{6})"))System.out.println("6 digits number identified");
Verifique o número do comprimento variável entre (assuma o comprimento 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 o número decimal de comprimento variável entre (Assuma o comprimento 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");
Com base em outras respostas, escrevi as minhas e não usa padrões ou análise com verificação de exceção.
Ele verifica no máximo um sinal de menos e no máximo um ponto decimal.
Aqui estão alguns exemplos e seus resultados:
"1", "-1", "-1,5" e "-1,556" retornam verdadeiro
"1..5", "1A.5", "1,5D", "-" e "--1" retornam falso
Nota: Se necessário, você pode modificar isso para aceitar um parâmetro Locale e passá-lo para as chamadas DecimalFormatSymbols.getInstance () para usar um Locale específico em vez do atual.
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;}
Aqui estão dois métodos que podem funcionar. (Sem usar exceções). Nota: Java é uma passagem por valor por padrão e o valor de uma String é o endereço dos dados do objeto da String. Então, quando você está fazendo
stringNumber = stringNumber.replaceAll(" ","");
Você alterou o valor de entrada para não ter espaços. Você pode remover essa linha, se quiser.
Aqui está outro método, caso você queira permitir flutuações. Esse método supostamente permite que números no formulário passem 1.123.123.123.123.123.123.
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, boa pergunta. Eu acho que este só funciona com números inteiros do tipo normal. O método foi criado inicialmente para filtrar números de telefone de entrada e contar números.
Integer.parseInt()
falharão ao analisar os números de celularNumberFormatException
.Respostas:
Com o Apache Commons Lang 3.5 e superior:
NumberUtils.isCreatable
ouStringUtils.isNumeric
.Com o Apache Commons Lang 3.4 e abaixo:
NumberUtils.isNumber
ouStringUtils.isNumeric
.Você também pode usar
StringUtils.isNumericSpace
quais retornostrue
para cadeias vazias e ignora os espaços internos na cadeia. Outra maneira é usar oNumberUtils.isParsable
que basicamente verifica se o número é analisável de acordo com o Java. (Os javadocs vinculados contêm exemplos detalhados para cada método.)fonte
StringUtils.isNumeric()
provavelmente não seria apropriado aqui, pois apenas verifica se a sequência é uma sequência de dígitos. Seria bom para a maioria ints mas não para números com decimais, separadores de grupos, etcStringUtils
não suporta sinais principais, mas deve verificarNumberUtils.isCreatable
, ele suporta os negativos corretamente.Isso geralmente é feito com uma função simples definida pelo usuário (ou seja, role a sua própria função "isNumeric").
Algo como:
No entanto, se você estiver chamando muito essa função e espera que muitas das verificações falhem por não ser um número, o desempenho desse mecanismo não será ótimo, pois você conta com exceções lançadas para cada falha, que é uma operação bastante cara.
Uma abordagem alternativa pode ser usar uma expressão regular para verificar a validade de ser um número:
Porém, tenha cuidado com o mecanismo RegEx acima, pois ele falhará se você estiver usando dígitos não árabes (ou seja, números diferentes de 0 a 9). Isso ocorre porque a parte "\ d" do RegEx corresponderá apenas a [0-9] e, efetivamente, não possui reconhecimento internacional de números. (Obrigado ao OregonGhost por apontar isso!)
Ou ainda outra alternativa é usar o objeto java.text.NumberFormat interno do Java para verificar se, após analisar a sequência de caracteres, a posição do analisador está no final da sequência. Se for, podemos assumir que a string inteira é numérica:
fonte
.
em seu regex corresponderá a qualquer caractere, não apenas ao caractere separador decimal.Se você estiver no Android, use:
documentação pode ser encontrada aqui
mantenha simples . principalmente todo mundo pode "reprogramar" (a mesma coisa).
fonte
.
,-
Expressões lambda do Java 8.
fonte
Como o @CraigTP mencionou em sua excelente resposta, também tenho preocupações semelhantes com o desempenho de usar Exceções para testar se a sequência é numérica ou não. Então, acabo dividindo a corda e o uso
java.lang.Character.isDigit()
.De acordo com o Javadoc ,
Character.isDigit(char)
reconhecerá corretamente dígitos não latinos. Em termos de desempenho, acho que um número N simples de comparações em que N é o número de caracteres na string seria mais eficiente em termos computacionais do que fazer uma correspondência de expressões regulares.ATUALIZAÇÃO: Conforme apontado por Jean-François Corbett no comentário, o código acima apenas validaria números inteiros positivos, o que cobre a maior parte do meu caso de uso. Abaixo está o código atualizado que valida corretamente os números decimais de acordo com o código do idioma padrão usado em seu sistema, com a suposição de que o separador decimal ocorre apenas uma vez na sequência.
fonte
toCharArray()
criará uma cópia da matriz no objeto String porque Strings são imutáveis. Provavelmente mais rápido para usar ocharAt(int index)
método diretamente no objeto String.StringIndexOutOfBoundsException
quando passada uma string com comprimento 0. pode ser corrigido comif(str.length() == 0) return false;
Biblioteca Goiaba do Google fornece um método auxiliar bom para fazer isso:
Ints.tryParse
. Você o usa como ele,Integer.parseInt
mas retorna, emnull
vez de lançar uma exceção, se a string não analisar um número inteiro válido. Observe que ele retorna Inteiro, não int, então você precisa convertê-lo / autobox novamente em int.Exemplo:
No entanto, a partir da versão atual - Guava r11 - ainda está marcada @Beta.
Eu não fiz benchmarking. Olhando para o código-fonte, existem algumas sobrecargas resultantes de muitas verificações de sanidade, mas no final elas usam
Character.digit(string.charAt(idx))
, semelhante, mas um pouco diferente da resposta de @Ibrahim acima. Não há exceções no tratamento de sobrecarga sob as coberturas em sua implementação.fonte
Não use Exceções para validar seus valores. Use Util libs como apache NumberUtils:
Editar :
Observe que, se sua string começar com 0, NumberUtils interpretará seu valor como hexadecimal.
fonte
Number.isNumber()
.Number.isNumber()
estava presente na primeira versão da resposta, de 24 de setembro de 12 às 17:01.Por que todos estão pressionando por soluções de exceção / regex?
Embora eu possa entender que a maioria das pessoas está bem em usar try / catch, se você quiser fazer isso com frequência ... pode ser extremamente desgastante.
O que fiz aqui foi pegar o regex, os métodos parseNumber () e o método de pesquisa de matriz para ver qual era o mais eficiente. Desta vez, eu olhei apenas para números inteiros.
Os resultados na velocidade que obtive foram:
Isenção de responsabilidade: não estou afirmando que esses métodos estão 100% otimizados, são apenas para demonstração dos dados
Exceções ganhas se e somente se o número tiver 4 caracteres ou menos, e cada string for sempre um número ... nesse caso, por que um cheque?
Em resumo, é extremamente doloroso se você encontrar números inválidos frequentemente com o try / catch, o que faz sentido. Uma regra importante que eu sempre sigo é NUNCA usar try / catch para o fluxo do programa . Este é um exemplo do porquê.
Curiosamente, o simples se char <0 || > 9 foi extremamente simples de escrever, fácil de lembrar (e deve funcionar em vários idiomas) e vence quase todos os cenários de teste.
A única desvantagem é que eu acho que Integer.parseInt () pode lidar com números não ASCII, enquanto o método de pesquisa de matriz não.
Para aqueles que se perguntam por que eu disse que é fácil lembrar a matriz de caracteres, se você sabe que não há sinais negativos, pode facilmente se safar com algo condensado como este:
Por fim, como nota final, fiquei curioso sobre o operador de atribuição no exemplo aceito com todos os votos. Adicionando na atribuição de
não é apenas inútil, pois você nem usa o valor, mas perde tempo de processamento e aumenta o tempo de execução em alguns nanossegundos (o que leva a um aumento de 100-200 ms nos testes). Não vejo por que alguém faria isso, pois na verdade é um trabalho extra para reduzir o desempenho.
Você pensaria que isso seria otimizado ... embora talvez eu deva verificar o bytecode e ver o que o compilador está fazendo. Isso não explica por que sempre apareceu como mais longo para mim, mas se de alguma forma é otimizado ... portanto, eu me pergunto o que está acontecendo. Como observação: por mais tempo, quero dizer executar o teste para 10000000 iterações e executar esse programa várias vezes (10x +) sempre mostrou que era mais lento.
EDIT: Atualizado um teste para Character.isDigit ()
fonte
A expressão regular do CraigTP (mostrada acima) produz alguns falsos positivos. Por exemplo, "23y4" será contado como um número porque '.' corresponde a qualquer caractere que não seja o ponto decimal.
Também rejeitará qualquer número com um '+' inicial
Uma alternativa que evita esses dois pequenos problemas é
fonte
true
para uma única mais"+"
ou menos"-"
, efalse
para"0."
"0."
é válidoDouble.parseDouble()
e é um literal válido de acordo com o JLS ( §3.10.2 )!matches("-?\\d+([.]\\d+)?")
Podemos tentar substituir todos os números da string fornecida por (""), ou seja, espaço em branco e, se depois disso, o comprimento da string for zero, podemos dizer que a string fornecida contém apenas números. [Se você achou esta resposta útil, por favor considere votar] Exemplo:
fonte
""
é um número, mas"3.14"
e"-1"
não é?Você pode usar
NumberFormat#parse
:fonte
value
.Se você usa java para desenvolver aplicativos Android, pode usar a função TextUtils.isDigitsOnly .
fonte
Aqui estava a minha resposta para o problema.
Um método catch all convenient que você pode usar para analisar qualquer String com qualquer tipo de analisador:
isParsable(Object parser, String str)
. O analisador pode ser umClass
ou umobject
. Isso também permite que você use analisadores personalizados que você escreveu e deve funcionar para qualquer cenário, por exemplo:Aqui está o meu código completo com descrições de métodos.
fonte
Para corresponder apenas números inteiros positivos de base dez, que contêm apenas dígitos ASCII, use:
fonte
Uma abordagem de bom desempenho, evitando tentativa de captura e manipulação de números negativos e notação científica.
fonte
Aqui está minha classe para verificar se uma string é numérica. Ele também corrige seqüências numéricas:
Recursos:
Aqui está...
fonte
Aqui está outro exemplo de regex "CraigTP" atualizado que corresponde a mais validações.
fonte
As exceções são caras, mas, neste caso, o RegEx leva muito mais tempo. O código abaixo mostra um teste simples de duas funções - uma usando exceções e outra usando regex. Na minha máquina, a versão RegEx é 10 vezes mais lenta que a exceção.
fonte
// verifique o código abaixo
fonte
fonte
Este é um exemplo simples para esta verificação:
fonte
Você pode usar o objeto java.util.Scanner.
fonte
Modifiquei a solução do CraigTP para aceitar notação científica e pontos e vírgulas como separadores decimais.
exemplo
fonte
É por isso que eu gosto da abordagem Try * no .NET. Além do método tradicional Parse, que é como o método Java, você também tem um método TryParse. Não sou bom em sintaxe Java (fora de parâmetros?), Portanto, trate o seguinte como algum tipo de pseudo-código. Deve deixar o conceito claro.
Uso:
fonte
Analise-o (ou seja, com
Integer#parseInt
) e simplesmente pegue a exceção. =)Para esclarecer: A função parseInt verifica se é possível analisar o número em qualquer caso (obviamente) e se você deseja analisá-lo de qualquer maneira, não será atingido nenhum desempenho ao realizar a análise.
Se você não deseja analisá-lo (ou analisá-lo muito, muito raramente), convém fazê-lo de maneira diferente, é claro.
fonte
Você pode usar NumberUtils.isCreatable () no Apache Commons Lang .
Como NumberUtils.isNumber será preterido na versão 4.0, use NumberUtils.isCreatable ().
fonte
Java 8 Stream, expressão lambda, interface funcional
Todos os casos tratados ( string nula, string vazia etc )
fonte
Ilustrei algumas condições para verificar números e decimais sem usar nenhuma API,
Verifique o comprimento do número fixo de 1 dígito
Verificar número do comprimento fixo (suponha que o comprimento seja 6)
Verifique o número do comprimento variável entre (assuma o comprimento de 4 a 6)
Verifique o número decimal de comprimento variável entre (Assuma o comprimento de 4 a 7)
Espero que ajude alguém.
fonte
Com base em outras respostas, escrevi as minhas e não usa padrões ou análise com verificação de exceção.
Ele verifica no máximo um sinal de menos e no máximo um ponto decimal.
Aqui estão alguns exemplos e seus resultados:
"1", "-1", "-1,5" e "-1,556" retornam verdadeiro
"1..5", "1A.5", "1,5D", "-" e "--1" retornam falso
Nota: Se necessário, você pode modificar isso para aceitar um parâmetro Locale e passá-lo para as chamadas DecimalFormatSymbols.getInstance () para usar um Locale específico em vez do atual.
fonte
Aqui estão dois métodos que podem funcionar. (Sem usar exceções). Nota: Java é uma passagem por valor por padrão e o valor de uma String é o endereço dos dados do objeto da String. Então, quando você está fazendo
Você alterou o valor de entrada para não ter espaços. Você pode remover essa linha, se quiser.
Aqui está outro método, caso você queira permitir flutuações. Esse método supostamente permite que números no formulário passem 1.123.123.123.123.123.123.
fonte