Stringa Java: verifica se una stringa contiene solo numeri e non lettere


196

Ho una stringa che carico in tutta la mia applicazione e cambia da numeri a lettere e simili. Ho una semplice ifdichiarazione per vedere se contiene lettere o numeri ma qualcosa non funziona correttamente. Ecco un frammento.

String text = "abc"; 
String number; 

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

Sebbene la textvariabile contenga lettere, la condizione ritorna come true. Il e &&dovrebbe valutare come entrambe le condizioni devono essere trueal fine di elaborare ilnumber = text;

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

Soluzione:

Sono stato in grado di risolvere questo problema utilizzando il seguente codice fornito da un commento su questa domanda. Anche tutti gli altri post sono validi!

Quello che ho usato che ha funzionato è venuto dal primo commento. Anche se tutti i codici di esempio forniti sembrano essere validi!

String text = "abc"; 
String number; 

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

5
contiene non accetta una regexp come input. Usa uno matches("\\d{2,}")o prova con un PatterneMatcher
Guillaume Polet

La stringa può avere un valore decimale o solo valori interi?
pseudoramble,

3
Perché stai controllando text.length ()> 2? Per quale motivo?
Codice entusiasta

1
@RedHatcc Pattern.matches("[a-zA-Z]+", text) == falsepuò essere semplificato in!Pattern.matches("[a-zA-Z]+", text)
SARose il

2
Utilizzo dell'API di streaming java dal boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));modulo Max MalyshPosta.
Yash,

Risposte:


356

Se elaborerai il numero come testo, quindi modifica:

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

per:

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

Invece di verificare che la stringa non contenga caratteri alfabetici, assicurati che contenga solo numeri.

Se si desidera effettivamente utilizzare il valore numerico, utilizzare Integer.parseInt()o Double.parseDouble()come altri hanno spiegato di seguito.


Come nota a margine, è generalmente considerata una cattiva pratica confrontare i valori booleani con trueo false. Basta usare if (condition)o if (!condition).


25
Probabilmente si desidera aggiungere ancore (ad esempio ^[0-9]+$), altrimenti abc123defverrà considerato un numero.
ICR,

10
Non credo sia necessario. matches()restituisce vero se e solo se si tratta di una corrispondenza completa dall'inizio alla fine.
Chthonic Project,

4
"^ -? \ d + \.? \ d * $" confronta l'intera stringa e corrisponde solo se è un numero valido (negativi e decimali inclusi). Ad esempio, corrisponderà a 1, 10, 1.0, -1, -1.0, ecc. Inoltre corrisponderà a "1". ma che spesso può essere analizzato comunque.

16
Non è necessario chiamare && (text.length() > 2). Tutto può essere verificato secondo il modello regex:if (text.matches("[0-9]{3,}")
ctomek,

Che dire virgole o punti per numeri che non sono numeri interi?
nibbana,

20

Puoi anche usare NumberUtil.isCreatable (String str) da Apache Commons


4
Non credo NumberUtil.isCreatable(String str)sia corretto usare per quello che la domanda originale chiede. Ad esempio, NumberUtil.isCreatable( "09" )restituisce false, anche se "09" contiene solo numeri .
Abdull

14

Ecco come lo farei:

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

Il $eviterà una corrispondenza parziale eg; 1B.


1
Non ho bisogno della text.length() > 2parte, quindi ho solo sostituito ^[0-9]*$da ^[0-9]+$essere sicuro di avere almeno un numero.
YB Causa

8

parseIntDal punto di vista delle prestazioni e simili sono molto peggiori rispetto ad altre soluzioni, perché almeno richiedono una gestione delle eccezioni.

Ho eseguito i test jmh e ho scoperto che iterare su String usando charAte confrontando i caratteri con i caratteri al contorno è il modo più veloce per verificare se la stringa contiene solo cifre.

Test JMH

I test confrontano le prestazioni di Character.isDigitvs Pattern.matcher().matchesvs Long.parseLongvs il controllo dei valori dei caratteri.

Questi modi possono produrre risultati diversi per stringhe non ascii e stringhe contenenti segni +/-.

I test vengono eseguiti in modalità Throughput ( maggiore è meglio ) con 5 iterazioni di riscaldamento e 5 iterazioni di test.

risultati

Si noti che parseLongè quasi 100 volte più lento rispetto isDigital primo carico di prova.

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

Suite di test

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

Aggiornato il 23 febbraio 2018

  • Aggiungi altri due casi: uno usando charAtinvece di creare array extra e un altro usando i IntStreamcodici char
  • Aggiungi l'interruzione immediata se non viene trovata una cifra per i casi di test in loop
  • Restituisce false per stringa vuota per casi di test in loop

Aggiornato il 23 febbraio 2018

  • Aggiungi un altro test case (il più veloce!) Che confronta il valore char senza usare lo stream

1
Se guardi il codice di toCharArray, sta allocando un array di caratteri e copiando i caratteri (penso che potrebbe essere costoso). Che dire se solo eseguissi l'iterazione della stringa usando un indice e un carattere, sarebbe più veloce? Sarebbe interessante anche se tu potessi aggiungere la soluzione di Andy ai tuoi test: isNum booleano = text.chars (). AllMatch (c -> c> = 48 && c <= 57)
Aldo Canepa

8

Per controllare semplicemente la stringa che contiene solo ALPHABETS usa il seguente codice:

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

Per controllare semplicemente la stringa che contiene solo NUMBER usa il seguente codice:

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

Spero che questo possa aiutare qualcuno!


3

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


1
per ridurre i numeri magici, puoi confrontare come segue:boolean isNum = text.chars().allMatch(c -> c >= '0' && c <= '9')
Phe0nix

2

Puoi usare Regex.Match

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

Oppure potresti usare versioni simili Integer.parseInt(String)o migliori Long.parseLong(String)per numeri più grandi come ad esempio:

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

E poi prova con:

if (onlyContainsNumbers(text) && text.length() > 2) {
    // do Stuff
}

.matches ("^ \\ d + $")
CrandellWS

2

Sotto regexs può essere usato per verificare se una stringa ha solo un numero o meno:

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

Entrambe le condizioni sopra restituiranno truese String contiene non numeri. On false, la stringa ha solo numeri.


2

Apache Commons Lang fornisce org.apache.commons.lang.StringUtils.isNumeric(CharSequence cs), che prende come argomento a Stringe controlla se è costituito da caratteri puramente numerici (inclusi numeri da script non latini). Tale metodo restituisce falsese sono presenti caratteri come spazio, meno, più e separatori decimali come virgola e punto.

Altri metodi di quella classe consentono ulteriori controlli numerici.


1
Questo dovrebbe essere molto più veloce di una regex; ecco l'implementazione: 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

Ci sono molte strutture per ottenere numeri da Strings in Java (e viceversa). Potresti voler saltare la parte regex per risparmiarti la complicazione.

Ad esempio, potresti provare a vedere cosa Double.parseDouble(String s)ritorna per te. Dovrebbe lanciare a NumberFormatExceptionse non trova un valore appropriato nella stringa. Suggerirei questa tecnica perché potresti effettivamente utilizzare il valore rappresentato da Stringcome tipo numerico.


5
Utilizzando un'eccezione come motivo per testare il tuo input potrebbe essere una cattiva idea, le eccezioni creano un grande sovraccarico.
Ofir Luzon,

1
@OfirLuzon Sono d'accordo sul fatto che le eccezioni non sono un ottimo modo per gestire i casi previsti che si presenteranno. Tuttavia, penso che sia difficile dire se ci sarebbe un colpo di performance senza più contesto.
pseudoramble

1

Ecco il mio codice, spero che questo ti possa aiutare!

 public boolean isDigitOnly(String text){

    boolean isDigit = false;

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

    return isDigit;
}

0

Questo codice è già stato scritto. Se non ti dispiace il colpo (estremamente) di prestazione minore - che probabilmente non è peggio che fare una corrispondenza regex - usa Integer.parseInt () o Double.parseDouble () . Questo ti dirà subito se una stringa è solo numeri (o è un numero, a seconda dei casi). Se è necessario gestire stringhe di numeri più lunghe, sia i costruttori sportivi BigInteger che BigDecimal che accettano le stringhe. Ognuno di questi genererà un NumberFormatException se si tenta di passargli un non-numero (integrale o decimale, ovviamente basato su quello che si sceglie). In alternativa, a seconda delle esigenze, basta iterare i caratteri nella stringa e selezionare Character.isDigit ()e / o Character.isLetter () .


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

0
Character first_letter_or_number = query.charAt(0);
                //------------------------------------------------------------------------------
                if (Character.isDigit())
                {

                }
                else if (Character.isLetter())
                {

                }

0

Esempio di test funzionante

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

Tuttavia, il codice può essere spezzato di "1a" ecc. Quindi è necessario controllare l'eccezione

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

Metodo per controllare no è stringa o no

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

0

È una cattiva pratica coinvolgere qualsiasi eccezione lanciare / maneggiare in uno scenario così tipico.

Quindi un parseInt () non è piacevole, ma un regex è una soluzione elegante per questo, ma prendersi cura dei seguenti:
-fractions
numeri -negative
separatore -decimal potrebbe differire in Contries ( '' es '' o)
-A volte è consentito avere un cosiddetto separatore delle migliaia, come uno spazio o una virgola, ad esempio 12.324.1000.355

Per gestire tutti i casi necessari nella tua applicazione devi fare attenzione, ma questa regex copre gli scenari tipici (positivo / negativo e frazionario, separati da un punto): ^ [- +]? \ D *.? \ D + $
For test, raccomando regexr.com .


0

Versione leggermente modificata di 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;
}
}

Ho dovuto usarlo oggi, quindi ho appena pubblicato le mie modifiche. Include valuta, migliaia di virgola o notazione del periodo e alcune convalide. Non include altre notazioni valutarie (euro, cent), le virgole di verifica sono ogni terza cifra.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.