Ordnen Sie mehrzeiligem Text mithilfe eines regulären Ausdrucks zu

Lesezeit: 6 Minuten

Ordnen Sie mehrzeiligem Text mithilfe eines regularen Ausdrucks zu
Nivas

Ich versuche, einen mehrzeiligen Text mit Java abzugleichen. Wenn ich die benutze Pattern Klasse mit der Pattern.MULTILINE Modifikator kann ich abgleichen, aber ich kann das nicht mit (?m).

Das gleiche Muster mit (?m) und verwenden String.matches scheint nicht zu funktionieren.

Ich bin mir sicher, dass ich etwas vermisse, 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?

Ordnen Sie mehrzeiligem Text mithilfe eines regularen Ausdrucks zu
Tim Pietzcker

Erstens verwenden Sie die Modifikatoren unter einer falschen Annahme.

Pattern.MULTILINE oder (?m) weist Java an, die Anker zu akzeptieren ^ und $ am Anfang und am Ende jeder Zeile übereinstimmen (ansonsten passen sie nur am Anfang/Ende der gesamten Zeichenfolge).

Pattern.DOTALL oder (?s) weist Java an, den Punkt auch mit Newline-Zeichen zu vergleichen.

Zweitens schlägt in Ihrem Fall die Regex fehl, weil Sie die verwenden matches() Methode, die erwartet, dass die Regex mit der übereinstimmt gesamte string – was natürlich nicht funktioniert, da danach noch einige Zeichen übrig sind (\\W)*(\\S)* abgestimmt haben.

Wenn Sie also einfach nach einer Zeichenfolge suchen, die mit beginnt User Comments:verwenden Sie die Regex

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

mit dem Pattern.DOTALL Möglichkeit:

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

ResultString enthält dann den Text danach User Comments:

  • Ich versuche, ein Muster zu finden, das mit jeder Zeichenfolge übereinstimmt, die mit “Benutzerkommentare:” beginnt. Danach ist “Benutzerkommentare:” etwas, das ein Benutzer in ein Textfeld eingibt und daher enthalten kann irgendetwas – sogar neue Zeilen. Sieht so aus, als müsste ich viel in Regex lernen …

    – Niwas

    6. September 2010 um 17:31 Uhr

  • Das funktioniert (danke!) Ich habe das Muster ausprobiert (?s)User Comments:\s*(.*) . Aus der Antwort von @Amarghosh habe ich das Muster bekommen User Comments: [\\s\\S]*. Unter diesen gibt es eine besser oder empfohlen Weise oder sind dies nur zwei verschiedene Möglichkeiten, dasselbe zu tun?

    – Niwas

    7. September 2010 um 7:05 Uhr

  • Beide meinen dasselbe; [\s\S] ist etwas expliziter (“entspricht jedem Zeichen, das entweder Leerzeichen oder Nicht-Leerzeichen ist”), . ist einfacher zu lesen, aber Sie müssen nach dem suchen (?s) oder DOTALL Modifikator, um herauszufinden, ob Zeilenumbrüche enthalten sind oder nicht. ich würde bevorzugen . mit dem Pattern.DOTALL Flag gesetzt (dies ist einfacher zu lesen und zu merken als (?s) nach meiner Meinung. Sie sollten das verwenden, womit Sie sich am wohlsten fühlen.

    – Tim Pietzcker

    7. September 2010 um 7:43 Uhr

  • .* mit DOTALL ist besser lesbar. Ich habe das andere verwendet, um zu zeigen, dass das Problem in den Unterschieden zwischen str.matches und matcher.find und nicht in den Flags liegt. +1

    – Amarghosch

    7. September 2010 um 8:41 Uhr


  • ich bevorzuge .* mit Pattern.DOTALLmuss aber mit (?s) gehen, weil ich verwenden muss String.matches.

    – Niwas

    8. September 2010 um 8:34 Uhr

Ordnen Sie mehrzeiligem Text mithilfe eines regularen Ausdrucks zu
Alan Moore

Das hat nichts mit dem MULTILINE-Flag zu tun; Was Sie sehen, ist der Unterschied zwischen dem find() und matches() Methoden. find() erfolgreich, wenn eine Übereinstimmung gefunden werden kann irgendwo in der Zielzeichenfolgewährend matches() erwartet, dass die Regex übereinstimmt die gesamte Saite.

Pattern p = Pattern.compile("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

Außerdem, 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 – das heißt, 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 $.

Normalerweise ^ stimmt mit dem Anfang der Zielzeichenfolge überein, und $ passt ganz am Ende (oder vor einem Zeilenumbruch am Ende, aber das lassen wir jetzt beiseite). Aber wenn die Zeichenfolge Zeilenumbrüche enthält, können Sie wählen ^ und $ um am Anfang und Ende einer beliebigen logischen Zeile, nicht nur am Anfang und Ende der gesamten Zeichenfolge, zu passen, indem Sie das MULTILINE-Flag setzen.

Also vergiss was MULTILINE bedeutet und denken Sie daran, was es ist tut: ändert das Verhalten der ^ und $ Anker. DOTALL Der Modus wurde ursprünglich “Single-Line” genannt (und ist in einigen Varianten immer noch vorhanden, einschließlich Perl und .NET), und er hat immer ähnliche Verwirrung gestiftet. Wir haben Glück, dass sich die Java-Entwickler in diesem Fall für den aussagekräftigeren Namen entschieden haben, aber es gab keine vernünftige Alternative für den “mehrzeiligen” Modus.

In Perl, wo dieser ganze Wahnsinn begann, haben sie ihren Fehler zugegeben und sowohl den “mehrzeiligen” als auch den “einzeiligen” Modus in den regulären Ausdrücken von Perl 6 losgeworden. In zwanzig Jahren wird vielleicht der Rest der Welt nachgezogen sein.

  • Kaum zu glauben, dass sie den Methodennamen “#matches” verwendet haben, um “matcht alle” zu bedeuten, huch

    – Rogerpack

    3. Dezember 2012 um 17:57 Uhr

  • @alan-moore Tut mir leid, dass ich das heruntergefahren habe, obwohl es richtig ist [ need more sleep 🙂 ]

    – Raymond Naseef

    22. Februar 2020 um 19:52 Uhr

1646246830 149 Ordnen Sie mehrzeiligem Text mithilfe eines regularen Ausdrucks zu
Amarghosch

str.matches(regex) benimmt sich wie Pattern.matches(regex, str) die versucht, die gesamte Eingabesequenz mit dem Muster abzugleichen und zurückgibt

true wenn, und nur wenn, die gesamte Eingabesequenz stimmt mit dem Muster dieses Matchers überein

Wohingegen matcher.find() Versuche zu finden die nächste Teilsequenz der Eingabesequenz, die mit dem Muster übereinstimmt und zurückkehrt

true wenn, und nur wenn, a Folge der Eingabesequenz mit dem Muster dieses Matchers übereinstimmt

Das Problem liegt also bei der Regex. Versuche Folgendes.

String test = "User Comments: This is \t a\ta \ntest\n\n message \n";

String pattern1 = "User Comments: [\\s\\S]*^test$[\\s\\S]*";
Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE);
System.out.println(p.matcher(test).find());  //true

String pattern2 = "(?m)User Comments: [\\s\\S]*^test$[\\s\\S]*";
System.out.println(test.matches(pattern2));  //true

Also kurz gesagt, die (\\W)*(\\S)* Teil in Ihrer ersten Regex stimmt mit einer leeren Zeichenfolge überein * bedeutet null oder mehr Vorkommen und die echte übereinstimmende Zeichenfolge ist User Comments: und nicht die ganze Zeichenfolge, wie Sie es erwarten würden. Der zweite schlägt fehl, da er versucht, die gesamte Zeichenfolge abzugleichen, dies jedoch nicht kann \\W entspricht einem Nicht-Wort-Zeichen, dh [^a-zA-Z0-9_] und das erste Zeichen ist Tein Wortzeichen.

  • Ich möchte jede Zeichenfolge abgleichen, die mit “Benutzerkommentare” beginnt, und die Zeichenfolge kann auch Zeilenumbrüche enthalten. Also habe ich das Muster verwendet User Comments: [\\s\\S]* und das hat funktioniert. (Danke!) Aus der Antwort von @Tim habe ich das Muster bekommen User Comments:(.*)das ist auch ok Nun, gibt es a empfohlen oder besser Weise unter diesen, oder sind dies nur zwei Möglichkeiten, dasselbe zu tun?

    – Niwas

    7. September 2010 um 7:00 Uhr


  • @Nivas Ich glaube nicht, dass es in Bezug auf die Leistung einen Unterschied geben würde. aber ich denke (.*) zusammen mit DOTALL flag ist offensichtlicher/lesbarer als ([\\s\\S]*)

    – Amarghosch

    7. September 2010 um 8:38 Uhr


  • Dies ist die beste Antwort …. bietet sowohl Zugriff auf Java-Code als auch auf Pattern String-Optionen für MultiLine-Fähigkeit.

    – GoldBischof

    21. März 2018 um 15:33 Uhr


Das Multiline-Flag weist Regex an, das Muster jeder Zeile und nicht der gesamten Zeichenfolge zuzuordnen. Für Ihre Zwecke reicht ein Platzhalter aus.

915040cookie-checkOrdnen Sie mehrzeiligem Text mithilfe eines regulären Ausdrucks zu

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy