Ich versuche, einen mehrzeiligen Text mit Java abzugleichen. Wenn ich die Pattern
Klasse mit dem Pattern.MULTILINE
Modifikator verwende, kann ich übereinstimmen, aber ich kann dies nicht tun(?m).
Das gleiche Muster mit (?m)
und unter Verwendung String.matches
scheint nicht zu funktionieren.
Ich bin sicher, ich vermisse etwas, aber keine Ahnung was. Bin nicht sehr gut in regulären Ausdrücken.
Das habe ich versucht
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*(.*)
. Aus der Antwort von @Amarghosh habe ich das Muster erhaltenUser Comments: [\\s\\S]*
. Unter diesen gibt es einen besseren oder empfohlenen Weg oder gibt es nur zwei verschiedene Wege, dasselbe zu tun?[\s\S]
ist etwas expliziter ("mit jedem Zeichen übereinstimmen, das entweder ein Leerzeichen oder ein Nicht-Leerzeichen ist"),.
ist leichter zu lesen, aber Sie müssen nach dem Modifikator(?s)
oder suchenDOTALL
, um herauszufinden, ob Zeilenumbrüche enthalten sind oder nicht. Ich würde es vorziehen, wenn.
diePattern.DOTALL
Flagge gesetzt ist (dies ist leichter zu lesen und zu merken als(?s)
meiner Meinung nach. Sie sollten das verwenden, womit Sie sich am wohlsten fühlen..*
mitDOTALL
ist besser lesbar. Ich habe den anderen verwendet, um zu zeigen, dass das Problem in den Unterschieden zwischen str.matches und matcher.find und nicht in den Flags liegt. +1.*
mitPattern.DOTALL
, muss aber mit (? S) gehen, weil ich verwenden mussString.matches
.Dies hat nichts mit dem MULTILINE-Flag zu tun. Was Sie sehen, ist der Unterschied zwischen den
find()
undmatches()
Methoden.find()
ist erfolgreich, wenn eine Übereinstimmung an einer beliebigen Stelle in der Zielzeichenfolge gefunden werden kann , währendmatches()
erwartet wird , dass der reguläre Ausdruck mit der gesamten Zeichenfolge übereinstimmt .Darüber hinaus
MULTILINE
bedeutet nicht, was Sie denken, dass es tut. Viele Leute scheinen zu dem Schluss zu kommen, dass Sie dieses Flag verwenden müssen, wenn Ihre Zielzeichenfolge Zeilenumbrüche enthält, dh wenn sie mehrere logische Zeilen enthält. Ich habe hier auf SO mehrere Antworten zu diesem Zweck gesehen, aber tatsächlich ändert dieses Flag nur das Verhalten der Anker,^
und$
.Entspricht normalerweise
^
dem Anfang der Zielzeichenfolge und$
dem Ende (oder vor einer neuen Zeile am Ende, aber das lassen wir vorerst beiseite). Wenn die Zeichenfolge jedoch Zeilenumbrüche enthält, können Sie am Anfang und am Ende jeder logischen Zeile und nicht nur am Anfang und Ende der gesamten Zeichenfolge auswählen^
und$
übereinstimmen, indem Sie das Flag MULTILINE setzen.Vergessen Sie also, was es
MULTILINE
bedeutet, und denken Sie daran, was es tut : Ändert das Verhalten der^
und$
Anker.DOTALL
Der Modus wurde ursprünglich als "einzeilig" bezeichnet (und ist immer noch in einigen Varianten erhältlich, einschließlich Perl und .NET), und hat immer zu ähnlicher Verwirrung geführt. Wir haben das Glück, dass die Java-Entwickler in diesem Fall den aussagekräftigeren Namen gewählt haben, aber es gab keine vernünftige Alternative für den "mehrzeiligen" Modus.In Perl, wo all dieser Wahnsinn begann, haben sie ihren Fehler eingestanden und sowohl den "mehrzeiligen" als auch den "einzeiligen" Modus in Perl 6-Regexen beseitigt. In weiteren zwanzig Jahren wird vielleicht der Rest der Welt nachziehen.
quelle
str.matches(regex)
verhält sich wiePattern.matches(regex, str)
der Versuch, die gesamte Eingabesequenz mit dem Muster abzugleichen, und kehrt zurückWährend
matcher.find()
versucht wird, die nächste Teilsequenz der Eingabesequenz zu finden, die dem Muster entspricht und zurückkehrtDas Problem liegt also bei der Regex. Versuche Folgendes.
Kurz gesagt, der
(\\W)*(\\S)*
Teil in Ihrem ersten regulären Ausdruck entspricht einer leeren Zeichenfolge, was*
bedeutet, dass keine oder mehrere Vorkommen vorhanden sind, und die tatsächlich übereinstimmende Zeichenfolge istUser Comments:
und nicht die gesamte Zeichenfolge, wie Sie es erwarten würden. Der zweite Fehler schlägt fehl, da er versucht, mit der gesamten Zeichenfolge übereinzustimmen, kann jedoch nicht\\W
mit einem Nicht-Wort-Zeichen übereinstimmen, dh[^a-zA-Z0-9_]
und das erste Zeichen istT
ein Wort-Zeichen.quelle
User Comments: [\\s\\S]*
und das hat funktioniert. (danke!) Aus der Antwort von @Tim habe ich das Muster erhaltenUser Comments:(.*)
, das ist auch in Ordnung. Gibt es nun einen empfohlenen oder besseren Weg unter diesen oder sind dies nur zwei Wege, dasselbe zu tun?(.*)
zusammen mitDOTALL
Flagge ist offensichtlicher / lesbarer als([\\s\\S]*)
Das mehrzeilige Flag weist Regex an, das Muster an jede Zeile anzupassen, im Gegensatz zur gesamten Zeichenfolge, damit für Ihre Zwecke ein Platzhalter ausreicht.
quelle