Cadena Java: vea si una cadena contiene solo números y no letras

195

Tengo una cadena que cargo en toda mi aplicación, y cambia de números a letras y demás. Tengo una ifdeclaración simple para ver si contiene letras o números, pero algo no funciona correctamente. Aquí hay un fragmento.

String text = "abc"; 
String number; 

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

Aunque la textvariable contiene letras, la condición regresa como true. El y &&debe evaluar ya que ambas condiciones tienen que estar truepara procesar elnumber = text;

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

Solución:

Pude resolver esto usando el siguiente código provisto por un comentario sobre esta pregunta. ¡Todas las demás publicaciones son válidas también!

Lo que usé que funcionó vino del primer comentario. ¡Aunque todos los códigos de ejemplo proporcionados también parecen ser válidos!

String text = "abc"; 
String number; 

if (Pattern.matches("[a-zA-Z]+", text) == false && text.length() > 2) {
    number = text; 
}
RedHatcc
fuente
55
contiene no toma una expresión regular como entrada. Úselo matches("\\d{2,}")o intente con una PatternyMatcher
Guillaume Polet
¿Puede la cadena tener un valor decimal o solo valores enteros?
pseudoramble
3
¿Por qué estás comprobando text.length ()> 2? ¿Cual es la razón?
Código entusiasta el
1
@RedHatcc Pattern.matches("[a-zA-Z]+", text) == falsese puede simplificar a!Pattern.matches("[a-zA-Z]+", text)
SARose
2
Usando el boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));formulario de API de transmisión Java Max Malysh.
Yash

Respuestas:

354

Si procesará el número como texto, cambie:

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

a:

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

En lugar de verificar que la cadena no contenga caracteres alfabéticos, asegúrese de que solo contenga números.

Si realmente desea usar el valor numérico, use Integer.parseInt()o Double.parseDouble()como otros han explicado a continuación.


Como nota al margen, generalmente se considera una mala práctica comparar valores booleanos con trueo false. Solo usa if (condition)o if (!condition).

Adam Liss
fuente
25
Probablemente desee agregar anclas (por ejemplo ^[0-9]+$), de lo contrario abc123defse considerará un número.
ICR
10
No creo que sea necesario. matches()devuelve verdadero si y solo si es una coincidencia completa de principio a fin.
Proyecto Chthonic
44
"^ -? \ d + \.? \ d * $" comparará toda la cadena y solo coincidirá si es un número válido (negativos y decimales incluidos). Por ejemplo, coincidirá con 1, 10, 1.0, -1, -1.0, etc. También coincidirá con "1". pero eso a menudo se puede analizar de todos modos.
16
No hay necesidad de llamar && (text.length() > 2). Todo se puede verificar en el patrón regex:if (text.matches("[0-9]{3,}")
ctomek
¿Qué pasa con comas o puntos para números que no son enteros?
nibbana
20

También puede usar NumberUtil.isCreatable (String str) de Apache Commons

Dhrumil Shah
fuente
44
No creo que NumberUtil.isCreatable(String str)sea ​​correcto usarlo para lo que pide la pregunta original. Por ejemplo, NumberUtil.isCreatable( "09" )retornos false, aunque "09" solo contenga números .
Abdull
14

Así es como lo haría:

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

El $evitará una coincidencia parcial, por ejemplo; 1B.

tokhi
fuente
1
No necesito la text.length() > 2parte, por lo que sólo sustituye ^[0-9]*$por ^[0-9]+$estar seguro de que tengo al menos un número.
YB Porque el
8

En cuanto al rendimiento parseInt, son mucho peores que otras soluciones, porque al menos requieren un manejo de excepciones.

He ejecutado pruebas jmh y he descubierto que iterar sobre String usando charAty comparando caracteres con caracteres de límite es la forma más rápida de probar si la cadena contiene solo dígitos.

Prueba de JMH

Las pruebas comparan el rendimiento de Character.isDigitvs Pattern.matcher().matchesvs Long.parseLongvs comprobación de valores de caracteres.

Estas formas pueden producir resultados diferentes para cadenas no ascii y cadenas que contienen signos +/-.

Las pruebas se ejecutan en modo de rendimiento ( mayor es mejor ) con 5 iteraciones de calentamiento y 5 iteraciones de prueba.

Resultados

Tenga en cuenta que parseLonges casi 100 veces más lento que isDigitpara la primera carga de prueba.

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

Banco de pruebas

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

Actualizado el 23 de febrero de 2018

  • Agregue dos casos más: uno usando en charAtlugar de crear una matriz adicional y otro usando IntStreamcódigos char
  • Agregue un descanso inmediato si no se encuentran dígitos para los casos de prueba en bucle
  • Devuelve falso para cadena vacía para casos de prueba en bucle

Actualizado el 23 de febrero de 2018

  • Agregue un caso de prueba más (¡el más rápido!) Que compara el valor de char sin usar stream
Anton R
fuente
1
Si nos fijamos en el código de toCharArray, está asignando una matriz de caracteres y copiando los caracteres (creo que podría ser costoso). ¿Qué pasa si solo itera la cadena usando un índice y charAt, sería más rápido? Sería interesante también si pudiera agregar la solución de Andy a sus pruebas: boolean isNum = text.chars (). AllMatch (c -> c> = 48 && c <= 57)
Aldo Canepa
8

Para verificar simplemente la cadena que contiene solo ALPHABETS, use el siguiente código:

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

Para verificar simplemente la cadena que contiene solo NUMBER use el siguiente código:

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

Espero que esto ayude a alguien!

Aman Kumar Gupta
fuente
3

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

Andy
fuente
1
para reducir los números mágicos, puede comparar de la siguiente manera:boolean isNum = text.chars().allMatch(c -> c >= '0' && c <= '9')
Phe0nix
2

Puedes usar Regex.Match

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

O puede usar versiones similares Integer.parseInt(String)o mejores Long.parseLong(String)para números más grandes como, por ejemplo:

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

Y luego prueba con:

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

Las expresiones regulares a continuación se pueden usar para verificar si una cadena tiene solo un número o no:

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

Ambas condiciones anteriores se devolverán truesi String no contiene números. Encendido false, la cadena solo tiene números.

Nitesh Shrivastava
fuente
2

Apache Commons Lang proporciona org.apache.commons.lang.StringUtils.isNumeric(CharSequence cs), que toma como argumento Stringay comprueba si consta de caracteres puramente numéricos (incluidos números de scripts no latinos). Ese método devuelve falsesi hay caracteres como espacio, menos, más y separadores decimales como coma y punto.

Otros métodos de esa clase permiten más controles numéricos.

Abdull
fuente
1
Esto debería ser mucho más rápido que una expresión regular; Aquí está la implementación: 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

Hay muchas facilidades para obtener números de Strings en Java (y viceversa). Es posible que desee omitir la parte de expresiones regulares para evitar la complicación de eso.

Por ejemplo, podría intentar ver qué le Double.parseDouble(String s)devuelve. Debería arrojar un NumberFormatExceptionsi no encuentra un valor apropiado en la cadena. Sugeriría esta técnica porque en realidad podría hacer uso del valor representado por el Stringcomo un tipo numérico.

pseudoramble
fuente
55
Usar una excepción como un motivo para probar su entrada puede ser una mala idea, las excepciones crean una gran sobrecarga.
Ofir Luzon
1
@OfirLuzon Estoy de acuerdo en que las excepciones no son una excelente manera de manejar los casos esperados que van a surgir. Sin embargo, creo que es difícil saber si habría un impacto en el rendimiento sin más contexto.
pseudoramble
1

Aquí está mi código, ¡espero que esto te ayude!

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

Este código ya está escrito. Si no le importa el impacto de rendimiento (extremadamente) menor, que probablemente no sea peor que hacer una coincidencia de expresiones regulares, use Integer.parseInt () o Double.parseDouble () . Eso le dirá de inmediato si una cadena es solo números (o es un número, según corresponda). Si necesita manejar cadenas de números más largas, constructores deportivos BigInteger y BigDecimal que aceptan cadenas. Cualquiera de estos arrojará una NumberFormatException si intenta pasar un no número (integral o decimal, basado en el que elija, por supuesto). Alternativamente, dependiendo de sus requisitos, solo itere los caracteres en la Cadena y marque Character.isDigit ()y / o Character.isLetter () .

Ryan Stewart
fuente
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
fuente
0
Character first_letter_or_number = query.charAt(0);
                //------------------------------------------------------------------------------
                if (Character.isDigit())
                {

                }
                else if (Character.isLetter())
                {

                }
JamisonMan111
fuente
0

Ejemplo de prueba de trabajo

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

Aún así, su código se puede dividir en "1a", etc.

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 que no es cadena o no

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

Es una mala práctica involucrar cualquier lanzamiento / manejo de excepción en un escenario tan típico.

Por lo tanto un parseInt () no es agradable, pero una expresión regular es una solución elegante para esto, pero tenga cuidado de lo siguiente:
-fractions
números negativos al
separador -decimal podría diferir en Contries ( '' ejemplo '', o)
-a veces se le permite tener un llamado separador de miles, como un espacio o una coma, por ejemplo, 12,324,1000.355

Para manejar todos los casos necesarios en su aplicación, debe tener cuidado, pero esta expresión regular cubre los escenarios típicos (positivo / negativo y fraccionario, separados por un punto): ^ [- +]? \ D *.? \ D + $
For prueba, recomiendo regexr.com .

Adam Bodrogi
fuente
0

Versión ligeramente 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;
}
}

Tuve que usar esto hoy, así que acabo de publicar mis modificaciones. Incluye moneda, miles de notación de coma o punto, y algunas validaciones. No incluye otras anotaciones de moneda (euro, centavo), las comas de verificación son cada tercer dígito.

usuario176692
fuente