String Java - Veja se uma string contém apenas números e não letras

195

Eu tenho uma string que eu carrego em todo o meu aplicativo, e ela muda de números para letras e tal. Eu tenho uma ifdeclaração simples para ver se ele contém letras ou números, mas algo não está funcionando corretamente. Aqui está um trecho.

String text = "abc"; 
String number; 

if (text.contains("[a-zA-Z]+") == false && text.length() > 2) {
    number = text; 
}

Embora a textvariável contenha letras, a condição retorna como true. A e &&deve avaliar, pois ambas as condições precisam estar trueem ordem para processar onumber = text;

==============================

Solução:

Consegui resolver isso usando o código a seguir fornecido por um comentário sobre essa pergunta. Todas as outras postagens também são válidas!

O que eu usei que funcionou veio do primeiro comentário. Embora todos os códigos de exemplo fornecidos pareçam válidos também!

String text = "abc"; 
String number; 

if (Pattern.matches("[a-zA-Z]+", text) == false && text.length() > 2) {
    number = text; 
}
RedHatcc
fonte
5
contém não recebe um regexp como entrada. Use matches("\\d{2,}")ou tente com um PatterneMatcher
Guillaume Polet
A string pode ter um valor decimal ou apenas valores inteiros?
Pseudoramble
3
Por que você está verificando text.length ()> 2? Qual o motivo?
Code Enthusiastic
1
O @RedHatcc Pattern.matches("[a-zA-Z]+", text) == falsepode ser simplificado para!Pattern.matches("[a-zA-Z]+", text)
SARose
2
Usando o boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));formulário de API de streaming de java Max MalyshPost.
Yash

Respostas:

354

Se você estiver processando o número como texto, altere:

if (text.contains("[a-zA-Z]+") == false && text.length() > 2){

para:

if (text.matches("[0-9]+") && text.length() > 2) {

Em vez de verificar se a sequência não contém caracteres alfabéticos, verifique se ela contém apenas números.

Se você realmente deseja usar o valor numérico, use Integer.parseInt()ou Double.parseDouble()conforme explicado abaixo.


Como observação, geralmente é considerado uma prática ruim comparar valores booleanos com trueou false. Basta usar if (condition)ou if (!condition).

Adam Liss
fonte
25
Você provavelmente deseja adicionar âncoras (por exemplo ^[0-9]+$), caso contrário abc123def, será considerado um número.
ICR
10
Eu não acho que isso é necessário. matches()retorna true se e somente se for uma correspondência completa do começo ao fim.
Chthonic Project
4
"^ -? \ d + \.? \ d * $" comparará a cadeia inteira e corresponderá apenas se for um número válido (negativos e decimais incluídos). Por exemplo, ele corresponderá a 1, 10, 1,0, -1, -1,0 etc. etc. Também corresponderá a "1". mas isso geralmente pode ser analisado de qualquer maneira.
16
Não há necessidade de ligar && (text.length() > 2). Tudo pode ser verificado no padrão regex:if (text.matches("[0-9]{3,}")
ctomek 26/10/2015
E vírgulas ou pontos para números que não são inteiros?
nibbana 18/04
20

Você também pode usar NumberUtil.isCreatable (String str) no Apache Commons

Dhrumil Shah
fonte
4
Não acho NumberUtil.isCreatable(String str)correto usar o que a pergunta original pede. Por exemplo, NumberUtil.isCreatable( "09" )retorna false, mesmo que "09" contenha apenas números .
Abdull
14

É assim que eu faria:

if(text.matches("^[0-9]*$") && text.length() > 2){
    //...
}

O $evitará uma correspondência parcial, por exemplo; 1B.

tokhi
fonte
1
Eu não preciso da text.length() > 2parte, então eu apenas substituído ^[0-9]*$por ^[0-9]+$ter certeza que eu tenho pelo menos um número.
YB Causa
8

Em termos de desempenho, parseIntessas são muito mais piores do que outras soluções, porque pelo menos exigem tratamento de exceção.

Fiz testes jmh e descobri que a iteração sobre String usando charAte comparando caracteres com caracteres de limite é a maneira mais rápida de testar se a string contém apenas dígitos.

Teste JMH

Os testes comparam o desempenho de Character.isDigitvs Pattern.matcher().matchesvs Long.parseLongvs valores de caracteres.

Essas maneiras podem produzir resultados diferentes para cadeias não-ascii e cadeias contendo sinais +/-.

Os testes são executados no modo Taxa de transferência (quanto maior, melhor ) com 5 iterações de aquecimento e 5 iterações de teste.

Resultados

Observe que parseLongé quase 100 vezes mais lento que isDigitna primeira carga de teste.

## Test load with 25% valid strings (75% strings contain non-digit symbols)

Benchmark       Mode  Cnt  Score   Error  Units
testIsDigit    thrpt    5  9.275 ± 2.348  ops/s
testPattern    thrpt    5  2.135 ± 0.697  ops/s
testParseLong  thrpt    5  0.166 ± 0.021  ops/s

## Test load with 50% valid strings (50% strings contain non-digit symbols)

Benchmark              Mode  Cnt  Score   Error  Units
testCharBetween       thrpt    5  16.773 ± 0.401  ops/s
testCharAtIsDigit     thrpt    5  8.917 ± 0.767  ops/s
testCharArrayIsDigit  thrpt    5  6.553 ± 0.425  ops/s
testPattern           thrpt    5  1.287 ± 0.057  ops/s
testIntStreamCodes    thrpt    5  0.966 ± 0.051  ops/s
testParseLong         thrpt    5  0.174 ± 0.013  ops/s
testParseInt          thrpt    5  0.078 ± 0.001  ops/s

Suíte de teste

@State(Scope.Benchmark)
public class StringIsNumberBenchmark {
    private static final long CYCLES = 1_000_000L;
    private static final String[] STRINGS = {"12345678901","98765432177","58745896328","35741596328", "123456789a1", "1a345678901", "1234567890 "};
    private static final Pattern PATTERN = Pattern.compile("\\d+");

    @Benchmark
    public void testPattern() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = PATTERN.matcher(s).matches();
            }
        }
    }

    @Benchmark
    public void testParseLong() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                try {
                    Long.parseLong(s);
                    b = true;
                } catch (NumberFormatException e) {
                    // no-op
                }
            }
        }
    }

    @Benchmark
    public void testCharArrayIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (char c : s.toCharArray()) {
                    b = Character.isDigit(c);
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testCharAtIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    b = Character.isDigit(s.charAt(j));
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testIntStreamCodes() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = s.chars().allMatch(c -> c > 47 && c < 58);
            }
        }
    }

    @Benchmark
    public void testCharBetween() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    char charr = s.charAt(j);
                    b = '0' <= charr && charr <= '9';
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }
}

Atualizado em 23 de fevereiro de 2018

  • Adicione mais dois casos - um usando em charAtvez de criar uma matriz extra e outro usando IntStreamcódigos de caracteres
  • Adicione interrupção imediata se não forem encontrados dígitos para casos de teste em loop
  • Retorno false para string vazia para casos de teste em loop

Atualizado em 23 de fevereiro de 2018

  • Adicione mais um caso de teste (o mais rápido!) Que compara o valor do char sem usar o stream
Anton R
fonte
1
Se você olhar para o código do toCharArray, ele está alocando uma matriz de caracteres e copiando os caracteres (acho que pode ser caro). E se você apenas iterar a string usando um índice e charAt, seria mais rápido? Seria interessante também se você pode adicionar a solução de Andy aos seus ensaios:. Boolean ISNUM = text.chars () allMatch (c -> c> = 48 && c <= 57)
Aldo Canepa
8

Para verificar simplesmente a string que contém apenas ALPHABETS, use o seguinte código:

if (text.matches("[a-zA-Z]+"){
   // your operations
}

Para verificar simplesmente a string que contém apenas NUMBER, use o seguinte código:

if (text.matches("[0-9]+"){
   // your operations
}

Espero que isso ajude alguém!

Aman Kumar Gupta
fonte
3

boolean isNum = text.chars (). allMatch (c -> c> = 48 && c <= 57)

Andy
fonte
1
para reduzir os números mágicos, você pode comparar da seguinte maneira:boolean isNum = text.chars().allMatch(c -> c >= '0' && c <= '9')
Phe0nix 20/09/19
2

Você pode usar o Regex.Match

if(text.matches("\\d*")&& text.length() > 2){
    System.out.println("number");
}

Ou você pode usar versões iguais Integer.parseInt(String)ou superiores Long.parseLong(String)a números maiores, como por exemplo:

private boolean onlyContainsNumbers(String text) {
    try {
        Long.parseLong(text);
        return true;
    } catch (NumberFormatException ex) {
        return false;
    }
} 

E depois teste com:

if (onlyContainsNumbers(text) && text.length() > 2) {
    // do Stuff
}
Yannjoel
fonte
.matches ("^ \\ d + $")
CrandellWS
2

As regexs abaixo podem ser usadas para verificar se uma sequência possui apenas número ou não:

if (str.matches(".*[^0-9].*")) or if (str.matches(".*\\D.*"))

Ambas as condições acima retornarão truese String contiver não números. Ativado false, a string possui apenas números.

Nitesh Shrivastava
fonte
2

O Apache Commons Lang fornece org.apache.commons.lang.StringUtils.isNumeric(CharSequence cs), que usa como argumento Stringae verifica se ele consiste em caracteres puramente numéricos (incluindo números de scripts não latinos). Esse método retornará falsese houver caracteres como espaço, menos, mais e separadores decimais, como vírgula e ponto.

Outros métodos dessa classe permitem mais verificações numéricas.

Abdull
fonte
1
Isso deve ser muito mais rápido que uma expressão regular; aqui está a implementação: public static boolean isNumeric(String str) { if (str == null) { return false; } else { int sz = str.length(); for(int i = 0; i < sz; ++i) { if (!Character.isDigit(str.charAt(i))) { return false; } } return true; } }
Leo
1

Existem muitas facilidades para obter números de Strings em Java (e vice-versa). Você pode pular a parte do regex para poupar a complicação disso.

Por exemplo, você pode tentar ver o que Double.parseDouble(String s)retorna para você. Deve lançar a NumberFormatExceptionse não encontrar um valor apropriado na string. Eu sugeriria essa técnica porque você poderia realmente usar o valor representado pelo Stringcomo um tipo numérico.

pseudoramble
fonte
5
Usar uma exceção como um motivo pelo qual testar sua entrada pode ser uma má idéia, as exceções criam uma grande sobrecarga.
Ofir Luzon
1
@OfirLuzon Concordo que as exceções não são uma ótima maneira de lidar com os casos esperados que surgirão. No entanto, acho difícil saber se haveria um impacto no desempenho sem mais contexto.
Pseudoramble
1

Aqui está o meu código, espero que isso ajude você!

 public boolean isDigitOnly(String text){

    boolean isDigit = false;

    if (text.matches("[0-9]+") && text.length() > 2) {
        isDigit = true;
    }else {
        isDigit = false;
    }

    return isDigit;
}
Saurabh Gaddelpalliwar
fonte
0

Este código já está escrito. Se você não se importa com o impacto (extremamente) de desempenho menor - o que provavelmente não é pior do que fazer uma correspondência de regex - use Integer.parseInt () ou Double.parseDouble () . Isso informará imediatamente se uma String é apenas um número (ou é um número, conforme apropriado). Se você precisar lidar com seqüências de números mais longas, os construtores de esporte BigInteger e BigDecimal que aceitam Strings. Qualquer uma dessas opções lançará uma NumberFormatException se você tentar passar um número não (integral ou decimal, com base na que você escolher, é claro). Como alternativa, dependendo dos seus requisitos, apenas itere os caracteres na String e marque Character.isDigit ()e / ou Character.isLetter () .

Ryan Stewart
fonte
0
import java.util.*;

class Class1 {
    public static void main(String[] argh) {
        boolean ans = CheckNumbers("123");
        if (ans == true) {
            System.out.println("String contains numbers only");
        } else {
            System.out.println("String contains other values as well");

        }
    }


    public static boolean CheckNumbers(String input) {
        for (int ctr = 0; ctr < input.length(); ctr++) {
            if ("1234567890".contains(Character.valueOf(input.charAt(ctr)).toString())) {
                continue;
            } else {
                return false;
            }
        }
        return true;
    }
}
Usman Javaid
fonte
0
Character first_letter_or_number = query.charAt(0);
                //------------------------------------------------------------------------------
                if (Character.isDigit())
                {

                }
                else if (Character.isLetter())
                {

                }
JamisonMan111
fonte
0

Exemplo de teste de trabalho

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

public class PaserNo {

    public static void main(String args[]) {

        String text = "gg";

        if (!StringUtils.isBlank(text)) {
            if (stringContainsNumber(text)) {
                int no=Integer.parseInt(text.trim());
                System.out.println("inside"+no);

            } else {
                System.out.println("Outside");
            }
        }
        System.out.println("Done");
    }

    public static boolean stringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }
}

Ainda assim, seu código pode ser quebrado por "1a" etc., portanto, você precisa verificar a exceção

if (!StringUtils.isBlank(studentNbr)) {
                try{
                    if (isStringContainsNumber(studentNbr)){
                    _account.setStudentNbr(Integer.parseInt(studentNbr.trim()));
                }
                }catch(Exception e){
                    e.printStackTrace();
                    logger.info("Exception during parse studentNbr"+e.getMessage());
                }
            }

Método para verificar não é string ou não

private boolean isStringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }
vaquar khan
fonte
0

É uma prática ruim envolver qualquer exceção lançando / manipulando um cenário tão típico.

Portanto, um parseInt () não é agradável, mas um regex é uma solução elegante para isso, mas cuidar do seguinte:
-fractions
números -negative
separador -decimal podem diferir em contries ( '' ex '' ou)
-Às vezes é permitido ter um chamado separador de milhar, como um espaço ou uma vírgula, por exemplo, 12.324.1000.355

Para lidar com todos os casos necessários no seu aplicativo, você deve ter cuidado, mas esse regex abrange os cenários típicos (positivo / negativo e fracionário, separados por um ponto): ^ [- +]? \ D *.? \ D + $
For teste, recomendo regexr.com .

Adam Bodrogi
fonte
0

Versão ligeiramente modificada de Adam Bodrogi:

public class NumericStr {


public static void main(String[] args) {
    System.out.println("Matches: "+NumericStr.isNumeric("20"));         // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("20,00"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30,000.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("-2980"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("$20"));            // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("jdl"));            // Should be false
    System.out.println("Matches: "+NumericStr.isNumeric("2lk0"));           // Should be false
}

public static boolean isNumeric(String stringVal) {
    if (stringVal.matches("^[\\$]?[-+]?[\\d\\.,]*[\\.,]?\\d+$")) {
        return true;
    }

    return false;
}
}

Tive que usar isso hoje, então apenas postei minhas modificações. Inclui moeda, milhares de vírgulas ou notação de período e algumas validações. Não inclui outras notações de moeda (euro, cent), vírgulas de verificação são de três em três dígitos.

user176692
fonte