web-dev-qa-db-fra.com

Groupe de capture optionnel Regex?

Après des heures de recherche, j'ai décidé de poser cette question. Pourquoi cette expression régulière: ^(dog).+?(cat)? ne fonctionne pas comme je pense que cela devrait fonctionner (capturer le premier chien et le chat s'il y en a)? Qu'est-ce que j'oublie ici?

dog, cat
dog, dog, cat
dog, dog, dog
19
forsajt

La raison pour laquelle vous n'obtenez pas un cat facultatif après un .+? Qualifié à contrecœur est qu'il est à la fois facultatif et non ancré: le moteur n'est pas obligé de faire cette correspondance, car il peut traiter légalement le cat comme la "queue" de la séquence .+?.

Si vous ancrez le chat à la fin de la chaîne, c'est-à-dire utilisez ^(dog).+?(cat)?$, vous obtiendrez une correspondance, cependant:

Pattern p = Pattern.compile("^(dog).+?(cat)?$");
for (String s : new String[] {"dog, cat", "dog, dog, cat", "dog, dog, dog"}) {
    Matcher m = p.matcher(s);
    if (m.find()) {
        System.out.println(m.group(1)+" "+m.group(2));
    }
}

Ceci imprime ( démo 1 )

dog cat
dog cat
dog null

Savez-vous par hasard comment y faire face au cas où il y aurait quelque chose après le chat?

Vous pouvez y faire face en construisant une expression plus délicate qui correspond à tout sauf à cat, comme ceci:

^(dog)(?:[^c]|c[^a]|ca[^t])+(cat)?

Maintenant, le cat peut se produire n'importe où dans la chaîne sans ancrage ( demo 2 ).

20
dasblinkenlight

La réponse de @ dasblinkenlight est excellente, mais voici un regexp qui améliore la 2e partie de celui-ci, quand on lui demande

Savez-vous par hasard comment y faire face au cas où il y aurait quelque chose après le chat?

La regexp ^(dog)(.+(cat))? vous obligerait à capturer le groupe no. 3 au lieu de 2 pour obtenir le chat en option, mais fonctionne tout aussi bien sans la supercherie caractère par caractère.

Et voici la démo (qui, encore une fois, est issue de la démo de @ dasblinkenlight qui m'a permis de bricoler et de trouver cette solution, merci encore!)

6
maltalef

L'extension de @ figha peut être étendue encore un peu plus, pour ne pas faire la deuxième capture inutile.

Utilisez ?: Pour rendre une partie entre crochets d'une expression régulière non capturable. Donc, l'expression régulière devient: ^(dog)(?:.+(cat))?

Encore une fois, voici le démo étendue et le test regex .

3
mft25