Regex non funziona in String.matches ()


147

Ho questo piccolo pezzo di codice

String[] words = {"{apf","hum_","dkoe","12f"};
for(String s:words)
{
    if(s.matches("[a-z]"))
    {
        System.out.println(s);
    }
}

Dovrebbe stampare

dkoe

ma non stampa nulla !!


41
Java matchesmette un ^ all'inizio e un $ alla fine delle regex per te. Quindi matches("[a-z]")cercherà effettivamente / ^ [az] $ / invece.
Robino,

Sì @Robino hai perfettamente ragione.
Mihir,

1
Sicuramente, se ti aspetti matchesdi cercare qualche occorrenza di [a-z], allora dovrebbe corrispondere a tutti loro? Non mi aspetterei matchesdi controllare ogni singolo personaggio singolarmente contro la regex.
PhilHibbs,

@Robino: dove è descritta / documentata quella funzionalità?
Toru,

@Toru Nella pagina dei documenti java per String.Matches - dove altro? Un casuale Google di "stringa java corrisponde alla documentazione" rivela, nel risultato più alto, la frase "str.matches (regex) produce esattamente lo stesso risultato dell'espressione". La parola importante è "esattamente".
Robino,

Risposte:


323

Benvenuti nel .matches()metodo sbagliato di Java ... Cerca e abbina TUTTO l'input. Sfortunatamente, altre lingue hanno seguito l'esempio :(

Se vuoi vedere se la regex corrisponde a un testo di input, usa a Pattern, a Matchere il .find()metodo del matcher:

Pattern p = Pattern.compile("[a-z]");
Matcher m = p.matcher(inputstring);
if (m.find())
    // match

Se quello che vuoi davvero è vedere se un input ha solo lettere minuscole, puoi usarlo .matches(), ma devi abbinare uno o più caratteri: aggiungi a +alla tua classe di caratteri, come in [a-z]+. Oppure usa ^[a-z]+$e .find().


2
trovo online centinaia di tutorial incompleti. Non ne ho trovato uno buono. Hai qualche suggerimento?
John

Grazie @fge per spiegare .matches(). Potresti sapere perché .find()funziona così lentamente in questo esempio ?
Konstantin Konopko,

3
Cosa intendi con altre lingue seguite l'esempio ? Da quello che so, solo C ++ ha un insieme equivalente di metodi - regex_searche regex_match. In Python, re.matchancora solo la corrispondenza all'inizio della stringa (come se fosse \Apattern) e Python 3.x ha un buon .fullmatch()metodo. In JS, Go, PHP e .NET, non esistono metodi regex che ancorino implicitamente la corrispondenza. ElasticSearch, XML Schema e HTML5 / Validators I pattern angluar sono sempre ancorati di default. In Swift / Objective C, c'è un modo per ancorare il pattern all'inizio con un'opzione.
Wiktor Stribiżew,

C'è un modo oneliner per farlo?
Cardinale - Ripristina Monica il

44

[a-z]corrisponde a un singolo carattere tra a e z. Quindi, se la tua stringa fosse "d", ad esempio, sarebbe stata abbinata e stampata.

Devi modificare la tua regex in modo [a-z]+che corrisponda a uno o più caratteri.


12
Ovviamente corrisponde a un singolo carattere, ecco cosa fa quel regexp! Ciò che non è chiaro comunque (e non dovrebbe essere nemmeno il caso!) È che java inserisca il prefisso ^e il suffisso $attorno al regexp fornito, alterandolo involontariamente e creando strani bug. Non dovrebbero farlo, perché non è così che intendeva la regexp iniziale.
klaar,

28

String.matchesrestituisce se l' intera stringa corrisponde alla regex, non solo a qualsiasi sottostringa.


3
Qualcosa che è davvero una triste realtà è che hai ragione. Davvero non so perché l'hanno fatto in questo modo.
Hola Soy Edu Feliz Navidad

16

L'implementazione di regex di java tenta di far corrispondere l'intera stringa

è diverso dalle perge regex, che cercano di trovare una parte corrispondente

se vuoi trovare una stringa con nient'altro che caratteri minuscoli, usa il modello [a-z]+

se si desidera trovare una stringa contenente almeno un carattere minuscolo, utilizzare il modello .*[a-z].*


maggiori informazioni qui
ycomp

3
Perché questo non è documentato ?!
Leo Orientis,

12

Usato

String[] words = {"{apf","hum_","dkoe","12f"};
    for(String s:words)
    {
        if(s.matches("[a-z]+"))
        {
            System.out.println(s);
        }
    }

4

Ho riscontrato lo stesso problema una volta:

Pattern ptr = Pattern.compile("^[a-zA-Z][\\']?[a-zA-Z\\s]+$");

Quanto sopra fallito!

Pattern ptr = Pattern.compile("(^[a-zA-Z][\\']?[a-zA-Z\\s]+$)");

Quanto sopra ha funzionato con pattern all'interno (e ).


2

La tua espressione regolare [a-z]non corrisponde dkoepoiché corrisponde solo a stringhe di lunghezza 1. Usa qualcosa di simile [a-z]+.


-1

è necessario inserire almeno una cattura ()nel modello in modo che corrisponda e correggere il modello in questo modo:

String[] words = {"{apf","hum_","dkoe","12f"};
for(String s:words)
{
    if(s.matches("(^[a-z]+$)"))
    {
        System.out.println(s);
    }
}

Le parentesi non hanno cambiato nulla.
Touniouk,

@Touniouk senza parentesi matchesnon ha alcun output.
MohsenB,

-3

Puoi rendere insensibile la custodia del tuo pattern facendo:

Pattern p = Pattern.compile("[a-z]+", Pattern.CASE_INSENSITIVE);
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.