Como verificar se uma String é numérica em Java

887

Como você verificaria se uma String era um número antes de analisá-la?

Craig Angus
fonte
36
Todas as soluções propostas com expressões regulares não funcionarão para números hexadecimais.
Oscar Castiblanco
e passar uma string nula na função correspondências (...) lançará a exceção NullPointer.
Hitesh Sahu
Veja a resposta de Max Malysh para obter uma solução concisa do Java 8 sem bibliotecas de terceiros.
Andy Thomas
@HiteshSahu cadeias nulas parecem estar graciosamente tratado em versão mais recente (incluindo 6.x Java e 7.x)
lifebalance
Todas as soluções propostas para uso Integer.parseInt()falharão ao analisar os números de celular NumberFormatException.
Não é um bug

Respostas:

691

Com o Apache Commons Lang 3.5 e superior: NumberUtils.isCreatableou StringUtils.isNumeric.

Com o Apache Commons Lang 3.4 e abaixo: NumberUtils.isNumberou StringUtils.isNumeric.

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.)

palacsint
fonte
59
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").

Algo como:

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

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:

public static boolean 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:

public static boolean isNumeric(String str) {
  NumberFormat formatter = NumberFormat.getInstance();
  ParsePosition pos = new ParsePosition(0);
  formatter.parse(str, pos);
  return str.length() == pos.getIndex();
}
CraigTP
fonte
7
\ 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
dantiston:
152

Se você estiver no Android, use:

android.text.TextUtils.isDigitsOnly(CharSequence str)

documentação pode ser encontrada aqui

mantenha simples . principalmente todo mundo pode "reprogramar" (a mesma coisa).

Ahmed Alejo
fonte
4
@ 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.
jwehrle
127

Expressões lambda do Java 8.

String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );
Max Malysh
fonte
4
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().

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

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.

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

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

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

    for ( char c : str.substring( 1 ).toCharArray() )
    {
        if ( !Character.isDigit( c ) )
        {
            if ( c == localeDecimalSeparator && !isDecimalSeparatorFound )
            {
                isDecimalSeparatorFound = true;
                continue;
            }
            return false;
        }
    }
    return true;
}
Ibrahim Arief
fonte
4
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.

Exemplo:

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

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.

quux00
fonte
Cuidado que isso geraria NPE caso o argumento seja nulo.
Vadzim
30

Não use Exceções para validar seus valores. Use Util libs como apache NumberUtils:

NumberUtils.isNumber(myStringValue);

Editar :

Observe que, se sua string começar com 0, NumberUtils interpretará seu valor como hexadecimal.

NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false
Goot
fonte
7
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.

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;
}

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 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

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:

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 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 ()

Água
fonte
4
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
Yo Apps
19
public static boolean isNumeric(String str)
{
    return str.matches("-?\\d+(.\\d+)?");
}

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 é

public static boolean isNumeric(String str)
{
    return str.matches("[+-]?\\d*(\\.\\d+)?");
}
user872985
fonte
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)
            return false; //To check if string is empty

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

        System.out.println(str);

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

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

        return str.replaceAll("[0-9]","").length() == 0;
    }
Ketan Ramteke
fonte
Então, ""é um número, mas "3.14"e "-1"não é?
Eric Duminil
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 é.
gbenroscience
12

Você pode usar NumberFormat#parse:

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}
Artem Barger
fonte
Ofereceu uma edição - .getInstance () estava ausente. +1, pois essa foi a resposta que tive ao encontrar esta pergunta.
precisa saber é o seguinte
5
Caro, se usado extensivamente
Daniel Nuriyev 03/02
1
Também passará se houver caracteres ilegíveis no final de value.
Brian White
Isso criaria um problema de sonar se você não registrar a exceção
jmhostalet
1
Isso funcionou para o formato de número 0x0001, onde Double.parseDouble não estava funcionando. 1)
Seabass77
11

Se você usa java para desenvolver aplicativos Android, pode usar a função TextUtils.isDigitsOnly .

Eric Guo
fonte
8

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 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 
 */
public static boolean isParsable(Object parser, String str) {
    Class theClass = (parser instanceof Class? (Class)parser: parser.getClass());
    boolean staticOnly = (parser == theClass), foundAtLeastOne = false;
    Method[] methods = theClass.getMethods();

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

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

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

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


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

Para corresponder apenas números inteiros positivos de base dez, que contêm apenas dígitos ASCII, use:

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

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+)?$" );

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

Aqui está minha classe para verificar se uma string é numérica. Ele também corrige seqüências numéricas:

Recursos:

  1. Remove zeros desnecessários ["12.0000000" -> "12"]
  2. Remove zeros desnecessários ["12.0580000" -> "12.058"]
  3. Remove caracteres não numéricos ["12.00sdfsdf00" -> "12"]
  4. Manipula valores negativos de seqüência de caracteres ["-12,020000" -> "-12,02"]
  5. Remove vários pontos ["-12.0.20.000" -> "-12.02"]
  6. Sem bibliotecas extras, apenas Java padrão

Aqui está...

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;
    }

}
Almôndega
fonte
5

Correspondência Regex

Aqui está outro exemplo de regex "CraigTP" atualizado que corresponde a mais validações.

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  1. Apenas um sinal negativo é -permitido e deve estar no começo.
  2. Após o sinal negativo, deve haver um dígito.
  3. Apenas um sinal decimal . permitido.
  4. Após o sinal decimal, deve haver um dígito.

Teste Regex

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

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

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;


public class IsNumeric {

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

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

public static void main(String [] args) {

    String test = "12345.F";

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

    System.out.println(after-before);

}

}
ChrisCantrell
fonte
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

public static boolean isDigitsOnly(CharSequence str) {
    final int len = str.length();
    for (int i = 0; i < len; i++) {
        if (!Character.isDigit(str.charAt(i))) {
            return false;
        }
    }
    return true;
}
Tejas Parmar
fonte
A pergunta diz "numérico", que pode incluir valores não inteiros.
Rghome #
3
// only int
public static boolean isNumber(int num) 
{
    return (num >= 48 && c <= 57); // 0 - 9
}

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

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

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

Este é um exemplo simples para esta verificação:

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

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

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

    return result;
}
ARIJIT
fonte
3

Você pode usar o objeto java.util.Scanner.

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

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 = new RegExp("^-?\d+([,\.]\d+)?([eE]-?\d+)?$");
re.test("-6546"); // true
re.test("-6546355e-4456"); // true
re.test("-6546.355e-4456"); // true, though debatable
re.test("-6546.35.5e-4456"); // false
re.test("-6546.35.5e-4456.6"); // false
AndyTheEntity
fonte
2

É 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);
        return true;
    } catch(NumberFormatException e) {
        return false;
    }
}

Uso:

int num;
if (parseInteger("23", out num)) {
    // Do something with num.
}
OregonGhost
fonte
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.

gha.st
fonte
1
Caro, se usado extensivamente
Daniel Nuriyev 03/02
Isso criaria um problema de sonar se você não registrar a exceção
jmhostalet
Double.parseDouble
Alex78191
2

Você pode usar NumberUtils.isCreatable () no Apache Commons Lang .

Como NumberUtils.isNumber será preterido na versão 4.0, use NumberUtils.isCreatable ().

Cenxui
fonte
2

Java 8 Stream, expressão lambda, interface funcional

Todos os casos tratados ( string nula, string vazia etc )

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

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

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 <= 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 o número decimal de comprimento variável entre (Assuma o comprimento 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 ajude alguém.

ArifMustafa
fonte
2

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.

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

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

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

    var isDecimalSeparatorFound = false;

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

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

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.

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;
}

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.

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

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

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

            if(!commaFound)
            {
                countOfDigitsBeforeFirstComma++;
            }

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

    if((decimalPointPassed)&&((countOfDigitsBeforeDecimalPoint==0)||(countOfDigitsAfterDecimalPoint==0)))
    {
        return false;
    }
    return true;
}
XForCE07
fonte
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.
XForCE07