Faire correspondre le texte multiligne à l’aide d’une expression régulière

J’essaie de faire correspondre un texte à plusieurs lignes en utilisant java. Lorsque j’utilise la classe Pattern avec le modificateur Pattern.MULTILINE , je suis capable de correspondre, mais je ne peux pas le faire avec (?m).

Le même modèle avec (?m) et en utilisant Ssortingng.matches ne semble pas fonctionner.

Je suis sûr que je manque quelque chose, mais aucune idée de quoi. Je ne suis pas très bon en expressions régulières.

C’est ce que j’ai essayé

 Ssortingng test = "User Comments: This is \ta\ta \n test \n\n message \n"; Ssortingng pattern1 = "User Comments: (\\W)*(\\S)*"; Pattern p = Pattern.comstack(pattern1, Pattern.MULTILINE); System.out.println(p.matcher(test).find()); //true Ssortingng pattern2 = "(?m)User Comments: (\\W)*(\\S)*"; System.out.println(test.matches(pattern2)); //false - why? 

Tout d’abord, vous utilisez les modificateurs sous une hypothèse incorrecte.

Pattern.MULTILINE ou (?m) indique à Java d’accepter les ancres ^ et $ pour correspondre au début et à la fin de chaque ligne (sinon, elles ne correspondent qu’au début / à la fin de la chaîne entière).

Pattern.DOTALL ou (?s) indique à Java d’autoriser le point à correspondre aux caractères de nouvelle ligne.

Deuxièmement, dans votre cas, le regex échoue parce que vous utilisez la méthode matches() , qui s’attend à ce que l’expression régulière corresponde à la chaîne entière , ce qui ne fonctionne évidemment pas car il rest quelques caractères après (\\W)*(\\S)* ont correspondu.

Donc, si vous cherchez simplement une chaîne commençant par User Comments: utilisez la regex

 ^\s*User Comments:\s*(.*) 

avec l’option Pattern.DOTALL :

 Pattern regex = Pattern.comstack("^\\s*User Comments:\\s+(.*)", Pattern.DOTALL); Matcher regexMatcher = regex.matcher(subjectSsortingng); if (regexMatcher.find()) { ResultSsortingng = regexMatcher.group(1); } 

ResultSsortingng contiendra alors le texte après User Comments:

Cela n’a rien à voir avec le drapeau MULTILINE; Ce que vous voyez est la différence entre les méthodes find() et matches() . find() réussit si une correspondance peut être trouvée n’importe où dans la chaîne cible , tandis que matches() attend que l’expression rationnelle corresponde à la chaîne entière .

 Pattern p = Pattern.comstack("xyz"); Matcher m = p.matcher("123xyzabc"); System.out.println(m.find()); // true System.out.println(m.matches()); // false Matcher m = p.matcher("xyz"); System.out.println(m.matches()); // true 

De plus, MULTILINE ne signifie pas ce que vous pensez. Beaucoup de personnes semblent aller jusqu’à la conclusion que vous devez utiliser cet indicateur si votre chaîne cible contient des nouvelles lignes, c’est-à-dire si elle contient plusieurs lignes logiques. J’ai vu plusieurs réponses ici sur SO à cet effet, mais en fait, tout ce que fait un drapeau change le comportement des ancres, ^ et $ .

Normalement ^ correspond au tout début de la chaîne cible et $ correspond à la toute fin (ou avant une nouvelle ligne à la fin, mais nous allons laisser cela de côté pour le moment). Mais si la chaîne contient des lignes nouvelles, vous pouvez choisir que ^ et $ correspondent au début et à la fin de chaque ligne logique, pas seulement au début et à la fin de la chaîne entière, en définissant le drapeau MULTILINE.

Alors oubliez ce que signifie MULTILINE et rappelez-vous simplement ce qu’il fait : change le comportement des ancres ^ et $ . DOTALL mode DOTALL s’appelait à l’origine “single-line” (et existe toujours dans certaines versions, y compris Perl et .NET), et il a toujours provoqué 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 pour le mode «multiligne».

En Perl, où toute cette folie a commencé, ils ont admis leur erreur et se sont débarrassés des modes “multiline” et “single-line” dans les regexes Perl 6. Dans vingt ans, le rest du monde aura peut-être suivi son exemple.

str.matches(regex) se comporte comme Pattern.matches(regex, str) qui tente de faire correspondre la séquence d’entrée entière au motif et renvoie

true si, et seulement si, toute la séquence d’entrée correspond au motif de ce matcher

Alors que matcher.find() tente de trouver la sous-séquence suivante de la séquence d’entrée qui correspond au modèle et renvoie

true si, et seulement si, une sous -séquence de la séquence d’entrée correspond à ce motif

Le problème est donc avec le regex. Essayez ce qui suit

 Ssortingng test = "User Comments: This is \ta\ta \ntest\n\n message \n"; Ssortingng pattern1 = "User Comments: [\\s\\S]*^test$[\\s\\S]*"; Pattern p = Pattern.comstack(pattern1, Pattern.MULTILINE); System.out.println(p.matcher(test).find()); //true Ssortingng pattern2 = "(?m)User Comments: [\\s\\S]*^test$[\\s\\S]*"; System.out.println(test.matches(pattern2)); //true 

Ainsi, en résumé, la partie (\\W)*(\\S)* de votre première regex correspond à une chaîne vide car * signifie zéro ou plusieurs occurrences et la chaîne correspondante est User Comments: et non la chaîne entière comme vous. d attendre. Le second échoue car il essaie de faire correspondre la chaîne entière, mais il ne peut pas le faire car \\W correspond à un caractère non mot, à savoir [^a-zA-Z0-9_] et le premier caractère est T , un caractère mot.