Regex ne fonctionne pas dans String.matches ()

147

J'ai ce petit bout de code

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

Censé imprimer

dkoe

mais ça n'imprime rien !!

John
la source
41
Java matchesmet un ^ au début et un $ à la fin des expressions rationnelles pour vous. Donc matches("[a-z]")recherchera en fait / ^ [az] $ / à la place.
Robino
Oui @Robino vous avez absolument raison.
Mihir
1
Sûrement, si vous prévoyez matchesde rechercher une occurrence de [a-z], alors il devrait correspondre à tous? Je ne m'attendrais pas matchesà vérifier chaque caractère individuellement par rapport à l'expression régulière.
PhilHibbs
@Robino: Où cette fonctionnalité est-elle décrite / documentée?
Toru le
@Toru Sur la page de documentation java pour String.Matches - où d'autre? Un Google occasionnel de "java string matches documentation" révèle, dans le premier résultat, l'expression "str.matches (regex) donne exactement le même résultat que l'expression". Le mot important est «exactement».
Robino le

Réponses:

323

Bienvenue dans la .matches()méthode mal nommée de Java ... Elle essaie et correspond à TOUTES les entrées. Malheureusement, d'autres langues ont emboîté le pas :(

Si vous voulez voir si l'expression régulière correspond à un texte d'entrée, utilisez a Pattern, a Matcheret la .find()méthode du matcher:

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

Si vous voulez effectivement voir si une entrée ne contient que des lettres minuscules, vous pouvez utiliser .matches(), mais vous devez faire correspondre un ou plusieurs caractères: ajoutez un +à votre classe de caractères, comme dans [a-z]+. Ou utilisez ^[a-z]+$et .find().

fge
la source
2
Je trouve des centaines de tutoriels incomplets en ligne. Je n'ai pas pu en trouver un bon. Avez-vous des suggestions?
John
Merci @fge pour expliquer .matches(). Peut-être savez-vous pourquoi .find()fonctionne si lentement dans cet exemple ?
Konstantin Konopko
3
Qu'entendez-vous par d' autres langues qui ont emboîté le pas ? D'après ce que je sais, seul C ++ a un ensemble équivalent de méthodes - regex_searchet regex_match. En Python, re.matchancre uniquement la correspondance au début de la chaîne (comme si c'était le cas \Apattern) et Python 3.x a une .fullmatch()méthode intéressante . Dans JS, Go, PHP et .NET, il n'y a pas de méthodes regex qui ancrent implicitement la correspondance. Les modèles ElasticSearch, XML Schema et HTML5 / Validators Angluar sont toujours ancrés par défaut. Dans Swift / Objective C, il existe un moyen d'ancrer le motif au début avec une option.
Wiktor Stribiżew
Existe-t-il un moyen de le faire en ligne?
Cardinal - Réintégrer Monica le
44

[a-z]correspond à un seul caractère entre a et z. Donc, si votre chaîne était juste "d", par exemple, elle aurait correspondu et aurait été imprimée.

Vous devez changer votre expression régulière pour [a-z]+qu'elle corresponde à un ou plusieurs caractères.

dogbane
la source
12
Bien sûr, cela correspond à un seul caractère, c'est ce que fait cette expression rationnelle! Ce qui n'est pas clair cependant (et ne devrait pas être le cas non plus!), C'est que java met le préfixe ^et le suffixe $autour de l'expression rationnelle fournie, la modifiant de manière indésirable et créant des bogues étranges. Ils ne devraient pas faire cela, car ce n'est pas ainsi que l'expression rationnelle initiale était conçue.
klaar
28

String.matchesrenvoie si la chaîne entière correspond à l'expression régulière, et non à n'importe quelle sous-chaîne.

yshavit
la source
3
Ce qui est vraiment une triste réalité, c'est que vous avez raison. Je ne sais vraiment pas pourquoi ils l'ont fait de cette façon.
Hola Soy Edu Feliz Navidad
16

L'implémentation java des expressions régulières essaie de faire correspondre la chaîne entière

c'est différent des expressions rationnelles perl, qui essaient de trouver une partie correspondante

si vous voulez trouver une chaîne avec rien d'autre que des minuscules, utilisez le modèle [a-z]+

si vous voulez trouver une chaîne contenant au moins un caractère minuscule, utilisez le modèle .*[a-z].*

Hachi
la source
plus d'infos ici
ycomp
3
Pourquoi n'est-ce pas documenté ?!
Leo Orientis
12

Utilisé

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

J'ai rencontré le même problème une fois:

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

Ce qui précède a échoué!

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

Ce qui précède a fonctionné avec un motif à l'intérieur (et ).

Shanta
la source
2

Votre expression régulière [a-z]ne correspond pas dkoecar elle ne correspond qu'aux chaînes de longueur 1. Utilisez quelque chose comme [a-z]+.


la source
-1

vous devez mettre au moins une capture ()dans le motif pour correspondre, et corriger le motif comme ceci:

String[] words = {"{apf","hum_","dkoe","12f"};
for(String s:words)
{
    if(s.matches("(^[a-z]+$)"))
    {
        System.out.println(s);
    }
}
MohsenB
la source
Les crochets n'ont rien changé.
Touniouk
@Touniouk sans crochets matchesn'a aucune sortie.
MohsenB
-3

Vous pouvez rendre votre modèle insensible à la casse en faisant:

Pattern p = Pattern.compile("[a-z]+", Pattern.CASE_INSENSITIVE);
Anita Kulkarni
la source