JavaRush /Java-Blog /Random-DE /Reguläre Ausdrücke in Java, Teil 3

Reguläre Ausdrücke in Java, Teil 3

Veröffentlicht in der Gruppe Random-DE
Wir präsentieren Ihnen eine Übersetzung einer kurzen Anleitung zu regulären Ausdrücken in Java, die Jeff Friesen für die Javaworld- Website geschrieben hat . Zur besseren Lesbarkeit haben wir den Artikel in mehrere Teile gegliedert. Reguläre Ausdrücke in Java, Teil 3 - 1Reguläre Ausdrücke in Java, Teil 1 Reguläre Ausdrücke in Java, Teil 2

Vereinfachen Sie häufige Programmieraufgaben mit der Regex-API

In Teil 1 und 2 dieses Artikels wurden Ihnen reguläre Ausdrücke und die Regex-API vorgestellt. Sie haben die Klasse kennengelernt Patternund sind Beispiele durchgegangen, die reguläre Ausdruckskonstrukte veranschaulichen, vom einfachen Mustervergleich mit Literalzeichenfolgen bis hin zum komplexeren Vergleich mit Bereichen, Grenzvergleichern und Quantifizierern. In diesem und den folgenden Teilen werden wir Themen behandeln, die im ersten Teil nicht behandelt wurden, und wir werden die entsprechenden Methoden der Klassen Pattern, Matcherund studieren PatternSyntaxException. Außerdem lernen Sie zwei Dienstprogramme kennen, die reguläre Ausdrücke verwenden , um häufige Programmierprobleme zu erleichtern. Der erste extrahiert Kommentare aus dem Code zur Dokumentation. Die zweite ist eine Bibliothek mit wiederverwendbarem Code zur Durchführung lexikalischer Analysen – ein wesentlicher Bestandteil von Assemblern, Compilern und ähnlicher Software.

QUELLCODE HERUNTERLADEN

Den gesamten Quellcode (erstellt von Jeff Friesen für JavaWorld) für die Demoanwendungen in diesem Artikel erhalten Sie hier .

Erlernen der Regex-API

Pattern, Matcherund PatternSyntaxExceptionsind die drei Klassen, aus denen die Regex-API besteht. Jeder von ihnen bietet Methoden, mit denen Sie reguläre Ausdrücke in Ihrem Code verwenden können.

Methoden der Pattern-Klasse

Eine Instanz einer Klasse Patternist ein kompilierter regulärer Ausdruck, auch Muster genannt. Reguläre Ausdrücke werden kompiliert, um die Leistung von Mustervergleichsvorgängen zu verbessern. Die folgenden statischen Methoden unterstützen die Kompilierung.
  • Pattern compile(String regex)Kompiliert den Inhalt regexin einer Zwischendarstellung, die in einem neuen gespeichert wird Pattern. Diese Methode gibt bei Erfolg entweder einen Verweis auf ein Objekt zurück oder löst eine Ausnahme aus, PatternSyntaxExceptionwenn eine ungültige Syntax für reguläre Ausdrücke erkannt wird. Jedes Objekt der Klasse Matcher, das von diesem Objekt verwendet Patternoder von ihm zurückgegeben wird, verwendet seine Standardeinstellungen, z. B. die Suche unter Berücksichtigung der Groß- und Kleinschreibung. Beispielsweise Pattern p = Pattern.compile("(?m)^\\."); erstellt das Code-Snippet ein Objekt Pattern, das eine kompilierte Darstellung eines regulären Ausdrucks speichert, um Zeichenfolgen abzugleichen, die mit einem Punktzeichen beginnen.

  • Pattern compile(String regex, int flags)löst das gleiche Problem wie Pattern compile(String regex), berücksichtigt jedoch Folgendes flags: eine Reihe von Bitkonstanten für Bitflags vom Typ OR. Die Klasse Patterndeklariert Konstanten CANON_EQ, CASE_INSENSITIVE, COMMENTS, DOTALL, LITERAL, MULTILINE, UNICODE_CASE, UNICODE_CHARACTER_CLASS и UNIX_LINES, die mit bitweisem ODER (z. B. CASE_INSENSITIVE | DOTALL) kombiniert und als Argument übergeben werden können flags.

  • Mit Ausnahme von CANON_EQ, LITERAL и UNICODE_CHARACTER_CLASSstellen diese Konstanten eine Alternative zu den in Teil 1 gezeigten verschachtelten Flag-Ausdrücken dar. Wenn eine andere Flag-Konstante als die in der Klasse definierten angetroffen wird Pattern, löst die Methode Pattern compile(String regex, int flags) eine Ausnahme aus java.lang.IllegalArgumentException. Entspricht beispielsweise Pattern p = Pattern.compile("^\\.", Pattern.MULTILINE);dem vorherigen Beispiel, wobei die Konstante Pattern.MULTILINEund der verschachtelte Flag-Ausdruck (?m)dasselbe bewirken.
Manchmal ist es notwendig, eine Kopie der ursprünglichen Zeichenfolge eines in ein Objekt kompilierten regulären Ausdrucks Patternzusammen mit den verwendeten Flags zu erhalten. Dazu können Sie folgende Methoden aufrufen:
  • String pattern()gibt die ursprüngliche Zeichenfolge des regulären Ausdrucks zurück, kompiliert in eine Pattern.

  • int flags()gibt die Flags des Objekts zurück Pattern.
Nach dem Empfang des Objekts Patternwird es normalerweise verwendet, um das Objekt abzurufen Matcherund Mustervergleichsvorgänge durchzuführen. Die Methode Matcher matcher(Charsequence input)erstellt ein Objekt Matcher, das Text inputnach einer Übereinstimmung mit einem Objektmuster durchsucht Pattern. Beim Aufruf wird eine Referenz auf dieses Objekt zurückgegeben Matcher. Beispielsweise gibt der Befehl für das Objekt Matcher m = p.matcher(args[1]);zurück , auf das die Variable verweist . MatcherPatternp
Einmalige Suche
static boolean matches(String regex, CharSequence input)Mit der Klassenmethode können Sie sich das Erstellen von Objekten und die einmalige Suche mithilfe einer Vorlage Patternsparen . Diese Methode gibt true zurück, wenn das Muster übereinstimmt , andernfalls gibt sie false zurück. Wenn der reguläre Ausdruck einen Syntaxfehler enthält, löst die Methode eine Ausnahme aus . Beispielsweise gibt prints aus , um zu bestätigen, dass die Phrase nur Leerzeichen und Kleinbuchstaben enthält. PatternMatcherinputregexPatternSyntaxExceptionSystem.out.println(Pattern.matches("[a-z[\\s]]*", "all lowercase letters and whitespace only"));trueall lowercase letters and whitespace only
Reguläre Ausdrücke in Java, Teil 3 - 2

Text aufteilen

Die meisten Entwickler haben mindestens einmal Code geschrieben, um Eingabetext in seine Bestandteile zu zerlegen, beispielsweise um ein textbasiertes Mitarbeiterkonto in eine Reihe von Feldern umzuwandeln. Die Klasse Patternbietet die Möglichkeit, diese mühsame Aufgabe mithilfe von zwei Textaufteilungsmethoden bequemer zu lösen:
  • Die Methode String[] split(CharSequence text, int limit)teilt textentsprechend den gefundenen Übereinstimmungen mit dem Objektmuster auf Patternund gibt die Ergebnisse in einem Array zurück. Jedes Array-Element gibt eine Textsequenz an, die von der nächsten Sequenz durch ein musterübereinstimmendes Textfragment (oder Textende) getrennt ist. Die Elemente des Arrays befinden sich in derselben Reihenfolge, in der sie in erscheinen text.

    Bei dieser Methode hängt die Anzahl der Array-Elemente vom Parameter ab limit, der auch die Anzahl der zu findenden Übereinstimmungen steuert.

    • Ein positiver Wert sucht nach nicht mehr als limit-1Übereinstimmungen und die Länge des Arrays beträgt nicht mehr als limitElemente.
    • Wenn der Wert negativ ist, werden alle möglichen Übereinstimmungen durchsucht und die Länge des Arrays kann beliebig sein.
    • Wenn der Wert Null ist, werden alle möglichen Übereinstimmungen durchsucht, die Länge des Arrays kann beliebig sein und leere Zeilen am Ende werden verworfen.

  • Die Methode String[] split(CharSequence text)ruft die vorherige Methode mit 0 als Grenzargument auf und gibt das Ergebnis ihres Aufrufs zurück.
Nachfolgend finden Sie die Ergebnisse der Methode split(CharSequence text)zur Lösung des Problems der Aufteilung eines Mitarbeiterkontos in separate Felder für Name, Alter, Postanschrift und Gehalt:
Pattern p = Pattern.compile(",\\s");
String[] fields = p.split("John Doe, 47, Hillsboro Road, 32000");
for (int i = 0; i < fields.length; i++)
   System.out.println(fields[i]);
Der obige Code beschreibt einen regulären Ausdruck zum Suchen eines Kommazeichens, direkt gefolgt von einem einzelnen Leerzeichen. Hier sind die Ergebnisse seiner Ausführung:
John Doe
47
Hillsboro Road
32000

Vorlagenprädikate und die Streams-API

In Java 8 Patternerschien eine Methode in der Klasse . Diese Methode erstellt ein Prädikat (eine Funktion mit einem booleschen Wert), das zum Abgleichen des Musters verwendet wird. Die Verwendung dieser Methode wird im folgenden Codeausschnitt gezeigt: Predicate asPredicate()
List progLangs = Arrays.asList("apl", "basic", "c", "c++", "c#", "cobol", "java", "javascript", "perl", "python", "scala");
Pattern p = Pattern.compile("^c");
progLangs.stream().filter(p.asPredicate()).forEach(System.out::println);
Dieser Code erstellt eine Liste von Programmiersprachennamen und kompiliert dann ein Muster, um alle Namen zu finden, die mit dem Buchstaben beginnen c. Die letzte Codezeile oben implementiert den Empfang eines seriellen Datenstroms mit dieser Liste als Quelle. Mithilfe einer booleschen Funktion wird ein Filter eingerichtet, asPredicate()der „true“ zurückgibt, wenn der Name mit einem Buchstaben beginnt c, den Stream durchläuft und übereinstimmende Namen auf der Standardausgabe ausgibt. Diese letzte Zeile entspricht der folgenden regulären Schleife, die aus der RegexDemo-Anwendung aus Teil 1 bekannt ist:
for (String progLang: progLangs)
   if (p.matcher(progLang).find())
      System.out.println(progLang);

Methoden der Matcher-Klasse

Eine Instanz der Klasse Matcherbeschreibt einen Mechanismus zum Durchführen von Mustervergleichsoperationen für eine Zeichenfolge durch Interpretation des kompilierten regulären Ausdrucks der Klasse Pattern. Objekte der Klasse Matcherunterstützen verschiedene Arten von Mustersuchoperationen:
  • Die Methode boolean find()durchsucht den Eingabetext nach der nächsten Übereinstimmung. Diese Methode beginnt mit dem Scannen entweder am Anfang des angegebenen Texts oder beim ersten Zeichen nach der vorherigen Übereinstimmung. Die zweite Option ist nur möglich, wenn der vorherige Aufruf dieser Methode „true“ zurückgegeben hat und der Resolver nicht zurückgesetzt wurde. In jedem Fall wird bei erfolgreicher Suche der boolesche Wert true zurückgegeben. Ein Beispiel für diese Methode finden Sie in RegexDemoTeil 1.

  • Die Methode boolean find(int start)setzt den Matcher zurück und durchsucht den Text nach der nächsten Übereinstimmung. Die Betrachtung beginnt an der durch den Parameter angegebenen Position start. Bei erfolgreicher Suche wird der boolesche Wert true zurückgegeben. Scannt beispielsweise m.find(1);den Text ab Position 1(Position 0 wird ignoriert). Wenn der Parameter starteinen negativen Wert oder einen Wert enthält, der größer als die Textlänge des Matchers ist, löst die Methode eine Ausnahme aus java.lang.IndexOutOfBoundsException.

  • Die Methode boolean matches()versucht, den gesamten Text einem Muster zuzuordnen. Es gibt den booleschen Wert „true“ zurück, wenn der gesamte Text mit dem Muster übereinstimmt. Beispielsweise wird der Code Pattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.matches());ausgegeben , falseweil das Zeichen !kein Wortzeichen ist.

  • Die Methode boolean lookingAt()versucht, den angegebenen Text mit dem Muster abzugleichen. Diese Methode gibt true zurück, wenn ein Teil des Textes mit dem Muster übereinstimmt. Im Gegensatz zur Methode matches();muss nicht der gesamte Text mit dem Muster übereinstimmen. Es wird beispielsweise Pattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.lookingAt());ausgegeben true, da der Anfang des Textes abc!nur aus wortbildenden Zeichen besteht.

Im Gegensatz zu Klassenobjekten behalten PatternKlassenobjekte MatcherStatusinformationen bei. Manchmal müssen Sie den Matcher möglicherweise zurücksetzen, um diese Informationen zu löschen, nachdem die Mustersuche abgeschlossen ist. Zum Zurücksetzen des Resolvers stehen folgende Methoden zur Verfügung:
  • Die Methode Matcher reset()setzt den Status des Matchers zurück, einschließlich der Position, die am Ende angehängt werden soll (auf 0 zurücksetzen). Der nächste Mustersuchvorgang beginnt am Anfang des Matcher-Textes. Gibt einen Verweis auf das aktuelle Objekt zurück Matcher. Setzt beispielsweise m.reset();den Resolver zurück, auf den verwiesen wird m.

  • Die Methode Matcher reset(CharSequence text)setzt den Resolver-Status zurück und setzt den neuen Resolver-Text auf text. Der nächste Mustersuchvorgang beginnt am Anfang des neuen Matcher-Textes. Gibt einen Verweis auf das aktuelle Objekt zurück Matcher. Setzt beispielsweise m.reset("new text");den referenzierten Resolver zurück mund legt den neuen Resolvertext auf fest "new text".

Reguläre Ausdrücke in Java, Teil 3 - 3

Text am Ende hinzufügen

Die Position des Matchers, der an das Ende angehängt werden soll, gibt den Anfang des Matcher-Textes an, der an das Ende des Objekts vom Typ angehängt wird java.lang.StringBuffer. Die folgenden Methoden verwenden diese Position:
  • Die Methode Matcher appendReplacement(StringBuffer sb, String replacement)liest die Matcher-Textzeichen und hängt sie an das Ende des Objekts, auf das StringBufferdas Argument verweist sb. Diese Methode stoppt das Lesen beim letzten Zeichen vor der vorherigen Musterübereinstimmung. Als nächstes hängt die Methode die Zeichen aus dem Objekt des Typs, Stringauf den das Argument verweist, replacementan das Ende des Objekts an StringBuffer(die Zeichenfolge replacementkann Verweise auf Textsequenzen enthalten, die während der vorherigen Suche erfasst wurden; diese werden anhand der ($)erfassten Zeichen und Gruppennummern angegeben). Schließlich legt die Methode den Wert der Matcher-Position fest, der an die Position des letzten übereinstimmenden Zeichens plus eins angehängt werden soll, und gibt dann einen Verweis auf den aktuellen Matcher zurück.

  • Die Methode Matcher appendReplacement(StringBuffer sb, String replacement)löst eine Ausnahme aus java.lang.IllegalStateException, wenn der Matcher noch keine Übereinstimmung gefunden hat oder ein vorheriger Suchversuch fehlgeschlagen ist. Es wird eine Ausnahme ausgelöst IndexOutOfBoundsException, wenn die Zeile replacementeine Capture-Gruppe angibt, die nicht im Muster enthalten ist.

  • Die Methode StringBuffer appendTail(StringBuffer sb)fügt den gesamten Text zu einem Objekt hinzu StringBufferund gibt einen Verweis auf dieses Objekt zurück. Rufen Sie nach dem letzten Methodenaufruf appendReplacement(StringBuffer sb, String replacement)die Methode auf, appendTail(StringBuffer sb)um den verbleibenden Text in das Objekt zu kopieren StringBuffer.

Erfasste Gruppen
Wie Sie sich aus Teil 1 erinnern, ist eine Erfassungsgruppe eine Folge von Zeichen, die in ()Metazeichen in Klammern ( ) eingeschlossen sind. Der Zweck dieses Konstrukts besteht darin, die gefundenen Zeichen zur späteren Wiederverwendung beim Mustervergleich zu speichern. Bei der Mustersuche werden alle Zeichen der erfassten Gruppe als Ganzes betrachtet.
Der folgende Code ruft die Methoden appendReplacement(StringBuffer sb, String replacement)und auf appendTail(StringBuffer sb, um alle Vorkommen der Zeichenfolge im Quelltext catdurch zu ersetzen caterpillar:
Pattern p = Pattern.compile("(cat)");
Matcher m = p.matcher("one cat, two cats, or three cats on a fence");
StringBuffer sb = new StringBuffer();
while (m.find())
   m.appendReplacement(sb, "$1erpillar");
m.appendTail(sb);
System.out.println(sb);
Durch die Verwendung einer erfassten Gruppe und eines Verweises darauf im Ersetzungstext wird das Programm angewiesen, erpillarnach jedem Vorkommen von einzufügen cat. Das Ergebnis der Ausführung dieses Codes sieht folgendermaßen aus: one caterpillar, two caterpillars, or three caterpillars on a fence

Text ersetzen

Die Klasse Matcherstellt uns zwei Methoden zur Textersetzung zur Verfügung, die die ergänzen appendReplacement(StringBuffer sb, String replacement). Mit diesen Methoden können Sie entweder das erste Vorkommen von [ersetzter Text] oder alle Vorkommen ersetzen:
  • Die Methode String replaceFirst(String replacement)setzt den Matcher zurück, erstellt ein neues Objekt String, kopiert alle Zeichen des Matcher-Textes (bis zum ersten Treffer) in diese Zeichenfolge, hängt die Zeichen von bis zum Ende an replacement, kopiert die verbleibenden Zeichen in die Zeichenfolge und gibt eine zurück Objekt String(die Zeichenfolge replacementkann Verweise auf die bei der vorherigen Suche erfassten Textsequenzen unter Verwendung von Dollarsymbolen und erfassten Gruppennummern enthalten).

  • Die Methode String replaceAll(String replacement)funktioniert ähnlich wie die Methode String replaceFirst(String replacement), ersetzt jedoch replacementalle gefundenen Übereinstimmungen durch Zeichen aus der Zeichenfolge.

Ein regulärer Ausdruck \s+sucht nach einem oder mehreren Leerzeichen im Eingabetext. Im Folgenden verwenden wir diesen regulären Ausdruck und rufen eine Methode replaceAll(String replacement)zum Entfernen doppelter Leerzeichen auf:
Pattern p = Pattern.compile("\\s+");
Matcher m = p.matcher("Удаляем      \t\t лишние пробелы.   ");
System.out.println(m.replaceAll(" "));
Hier sind die Ergebnisse: Удаляем лишние пробелы. Reguläre Ausdrücke in Java, Teil 4 Reguläre Ausdrücke in Java, Teil 5
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION