J'essaie de faire correspondre un texte sur plusieurs lignes en utilisant java. Lorsque j'utilise la Pattern
classe avec le Pattern.MULTILINE
modificateur, je peux faire correspondre, mais je ne peux pas le faire avec(?m).
Le même modèle avec (?m)
et en utilisant String.matches
ne semble pas fonctionner.
Je suis sûr qu'il me manque quelque chose, mais je ne sais pas quoi. Je ne suis pas très doué pour les expressions régulières.
C'est ce que j'ai essayé
String test = "User Comments: This is \t a\ta \n test \n\n message \n";
String pattern1 = "User Comments: (\\W)*(\\S)*";
Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE);
System.out.println(p.matcher(test).find()); //true
String pattern2 = "(?m)User Comments: (\\W)*(\\S)*";
System.out.println(test.matches(pattern2)); //false - why?
(?s)User Comments:\s*(.*)
. D'après la réponse de @Amarghosh, j'ai obtenu le modèleUser Comments: [\\s\\S]*
. Parmi ceux-ci, y a-t-il une manière meilleure ou recommandée ou s'agit-il simplement de deux façons différentes de faire la même chose?[\s\S]
est un peu plus explicite ("correspond à n'importe quel caractère qui est soit un espace ou non"),.
est plus facile à lire, mais vous devez rechercher le modificateur(?s)
ouDOTALL
afin de savoir si les retours à la ligne sont inclus ou non. Je préfère.
avec lePattern.DOTALL
jeu de drapeaux (c'est plus facile à lire et à retenir qu'à(?s)
mon avis. Vous devriez utiliser ce avec quoi vous vous sentez le plus à l'aise..*
avecDOTALL
est plus lisible. J'ai utilisé l'autre pour montrer que le problème réside dans les différences entre str.matches et matcher.find et non dans les indicateurs. +1.*
avecPattern.DOTALL
, mais je devrai aller avec (? S) car je dois utiliserString.matches
.Cela n'a rien à voir avec l'indicateur MULTILINE; ce que vous voyez est la différence entre les méthodes
find()
etmatches()
.find()
réussit si une correspondance peut être trouvée n'importe où dans la chaîne cible , tandis quematches()
s'attend à ce que l'expression régulière corresponde à la chaîne entière .De plus,
MULTILINE
cela ne signifie pas ce que vous pensez que cela fait. Beaucoup de gens semblent sauter à la conclusion que vous devez utiliser cet indicateur si votre chaîne cible contient des retours à la ligne, c'est-à-dire si elle contient plusieurs lignes logiques. J'ai vu plusieurs réponses ici sur SO à cet effet, mais en fait, ce drapeau ne fait que changer le comportement des ancres,^
et$
.Correspond normalement
^
au tout début de la chaîne cible et$
correspond à la toute fin (ou avant une nouvelle ligne à la fin, mais nous laisserons cela de côté pour l'instant). Mais si la chaîne contient des retours à la ligne, vous pouvez choisir pour^
et$
faire correspondre au début et à la fin de toute ligne logique, pas seulement au début et à la fin de la chaîne entière, en définissant l'indicateur MULTILINE.Alors oubliez ce que
MULTILINE
signifie et rappelez-vous simplement ce que cela fait : change le comportement des ancres^
et$
.DOTALL
Le mode était à l'origine appelé "single-line" (et l'est toujours dans certaines saveurs, y compris Perl et .NET), et il a toujours causé une confusion similaire. Nous avons la chance que les développeurs Java aient choisi le nom le plus descriptif dans ce cas, mais il n'y avait pas d'alternative raisonnable au mode "multiligne".En Perl, où toute cette folie a commencé, ils ont admis leur erreur et se sont débarrassés des modes "multiligne" et "simple ligne" dans les expressions rationnelles Perl 6. Dans vingt ans, peut-être que le reste du monde aura emboîté le pas.
la source
str.matches(regex)
se comporte commePattern.matches(regex, str)
qui tente de faire correspondre toute la séquence d'entrée avec le modèle et renvoieTandis que
matcher.find()
tente de trouver la sous-séquence suivante de la séquence d'entrée qui correspond au modèle et renvoieLe problème vient donc de l'expression régulière. Essayez ce qui suit.
Ainsi, en bref, la
(\\W)*(\\S)*
partie de votre première expression régulière correspond à une chaîne vide comme*
signifiant zéro ou plusieurs occurrences et la vraie chaîne correspondante estUser Comments:
et non la chaîne entière comme vous vous attendez. Le second échoue car il essaie de faire correspondre la chaîne entière mais il ne peut pas\\W
correspondre à un caractère non mot, c'est[^a-zA-Z0-9_]
-à- dire que le premier caractère estT
un caractère mot.la source
User Comments: [\\s\\S]*
et cela a fonctionné. (merci!) D'après la réponse de @Tim, j'ai obtenu le modèleUser Comments:(.*)
, c'est également correct. Maintenant, y a-t-il un moyen recommandé ou meilleur parmi ceux-ci, ou s'agit-il simplement de deux façons de faire la même chose?(.*)
leDOTALL
drapeau est plus évident / lisible que([\\s\\S]*)
L'indicateur multiligne indique à regex de faire correspondre le modèle à chaque ligne par opposition à la chaîne entière pour vos besoins, un caractère générique suffira.
la source