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

Reguläre Ausdrücke in Java, Teil 2

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 2 - 1Reguläre Ausdrücke in Java, Teil 1
Mehrere Bereiche zusammenführen
Sie können mehrere Bereiche zu einer einzigen Bereichszeichenklasse zusammenführen, indem Sie sie nebeneinander platzieren. Beispielsweise [a-zA-Z]gleicht die Klasse alle lateinischen Buchstaben in Klein- oder Großbuchstaben ab.

Mehrere Bereiche zusammenführen

Sie können mehrere Bereiche zu einer einzigen Bereichszeichenklasse zusammenführen, indem Sie sie nebeneinander platzieren. Beispielsweise [a-zA-Z]gleicht die Klasse alle lateinischen Buchstaben in Klein- oder Großbuchstaben ab.

Charakterklassen kombinieren

Eine Zeichenklassenvereinigung besteht aus mehreren verschachtelten Zeichenklassen und entspricht allen Zeichen in der resultierenden Vereinigung. Beispielsweise [a-d[m-p]]gleicht die Klasse die Zeichen von abis dund von mbis ab p. Betrachten Sie das folgende Beispiel: java RegexDemo [ab[c-e]] abcdef In diesem Beispiel werden die Zeichen a, b, und gefunden, cfür die es Übereinstimmungen in gibt : deabcdef
regex = [ab[c-e]]
input = abcdef
Found [a] starting at 0 and ending at 0
Found [b] starting at 1 and ending at 1
Found [c] starting at 2 and ending at 2
Found [d] starting at 3 and ending at 3
Found [e] starting at 4 and ending at 4

Schnittpunkt der Zeichenklasse

Die Schnittmenge der Zeichenklassen besteht aus Zeichen, die allen verschachtelten Klassen gemeinsam sind, und stimmt nur mit den gemeinsamen Zeichen überein. Beispielsweise [a-z&&[d-f]]entspricht die Klasse den Zeichen d, eund f. Betrachten Sie das folgende Beispiel: java RegexDemo "[aeiouy&&[y]]" party Beachten Sie, dass auf meinem Windows-Betriebssystem doppelte Anführungszeichen erforderlich sind, da die Befehlsshell sie &als Befehlstrennzeichen behandelt. In diesem Beispiel wird nur das Zeichen gefunden y, das eine Übereinstimmung hat in party:
regex = [aeiouy&&[y]]
input = party
Found [y] starting at 4 and ending at 4

Zeichenklassen subtrahieren

Subtrahierende Zeichenklassen umfassen alle Zeichen mit Ausnahme derjenigen, die in verschachtelten Zeichenklassen enthalten sind, und gleichen nur die verbleibenden Zeichen ab. Beispielsweise [a-z&&[^m-p]]gleicht die Klasse die Zeichen von abis lund von qbis ab z: java RegexDemo "[a-f&&[^a-c]&&[^e]]" abcdefg In diesem Beispiel werden die Zeichen gefunden d, ffür die es Übereinstimmungen gibt in abcdefg:
regex = [a-f&&[^a-c]&&[^e]]
input = abcdefg
Found [d] starting at 3 and ending at 3
Found [f] starting at 5 and ending at 5

Vordefinierte Zeichenklassen

Einige Zeichenklassen kommen in regulären Ausdrücken häufig genug vor , um die Verwendung der Kurzschreibweise zu rechtfertigen. Als solche Abkürzungen bietet die Klasse Patternvordefinierte Zeichenklassen an. Sie können sie verwenden, um Ihre regulären Ausdrücke zu vereinfachen und Syntaxfehler zu minimieren. Es gibt mehrere Kategorien vordefinierter Zeichenklassen: Standard-, POSIX- java.lang.Characterund Unicode-Eigenschaften wie Skript, Block, Kategorie und Binär. Die folgende Liste zeigt nur die Kategorie der Standardklassen:
  • \d: Nummer. Äquivalent [0-9].
  • \D: Nicht numerisches Zeichen. Äquivalent [^0-9].
  • \s: Leerzeichen. Äquivalent [ \t\n\x0B\f\r].
  • \S: Kein Leerzeichen. Äquivalent [^\s].
  • \w: Wortbildendes Symbol. Äquivalent [a-zA-Z_0-9].
  • \W: Kein wortbildendes Zeichen. Äquivalent [^\w].
Im folgenden Beispiel wird eine vordefinierte Zeichenklasse verwendet \w, um alle Wortzeichen im Eingabetext zu beschreiben: java RegexDemo \w "aZ.8 _" Schauen Sie sich die folgenden Ausführungsergebnisse genau an, die zeigen, dass Punkt- und Leerzeichen nicht als Wortzeichen gelten:
regex = \w
input = aZ.8 _
Found [a] starting at 0 and ending at 0
Found [Z] starting at 1 and ending at 1
Found [8] starting at 3 and ending at 3
Found [_] starting at 5 and ending at 5
Zeilentrenner
Die Klassen-SDK-Dokumentation Patternbeschreibt das Punkt-Metazeichen als eine vordefinierte Zeichenklasse, die mit jedem Zeichen außer Zeilentrennzeichen (ein- oder zweistellige Sequenzen, die das Ende einer Zeile markieren) übereinstimmt. Die Ausnahme bildet der Dotall-Modus (den wir als Nächstes besprechen), in dem Punkte auch mit Zeilentrennzeichen übereinstimmen. Die Klasse Patternunterscheidet folgende Zeilentrenner:
  • Wagenrücklaufzeichen ( \r);
  • Zeilenumbruchzeichen (Symbol zum Vorrücken des Papiers um eine Zeile) ( \n);
  • ein Wagenrücklaufzeichen, direkt gefolgt von einem Zeilenumbruchzeichen ( \r\n);
  • Nächstes Zeilenzeichen ( \u0085);
  • Zeilentrennzeichen ( \u2028);
  • Absatztrennzeichen ( \u2029)

Erfasste Gruppen

Die Erfassungsgruppe wird verwendet, um den gefundenen Zeichensatz zur weiteren Verwendung bei der Suche nach Muster zu speichern. Dieses Konstrukt ist eine Folge von Zeichen, die durch Klammern ( ( )) in Metazeichen eingeschlossen sind. Alle Zeichen innerhalb der erfassten Gruppe werden bei der Suche nach Muster als ein Ganzes betrachtet. Beispielsweise fasst die Erfassungsgruppe ( ) Javadie Buchstaben J, aund zu einer einzigen Einheit zusammen. Diese Erfassungsgruppe findet alle Vorkommen des Musters im Eingabetext. Bei jeder Übereinstimmung werden die zuvor gespeicherten Zeichen durch die nächsten ersetzt. Erfasste Gruppen können in anderen erfassten Gruppen verschachtelt werden. Beispielsweise ist in einem regulären Ausdruck eine Gruppe innerhalb einer Gruppe verschachtelt . Jeder verschachtelten oder nicht verschachtelten Erfassungsgruppe wird eine Nummer zugewiesen, beginnend bei 1, und die Nummerierung verläuft von links nach rechts. Im vorherigen Beispiel werden Capture-Gruppennummer 1 und Capture-Gruppennummer 2 abgeglichen . Im regulären Ausdruck werden Capture-Gruppennummer 1 und Capture-Gruppennummer 2 abgeglichen . Auf von Capture-Gruppen gespeicherte Übereinstimmungen kann später mithilfe von Rückverweisen zugegriffen werden. Die Rückreferenz wird als Backslash-Zeichen gefolgt von einem numerischen Zeichen angegeben, das der Nummer der erfassten Gruppe entspricht. Sie ermöglicht es Ihnen, auf Zeichen im von der Gruppe erfassten Text zu verweisen. Wenn ein Backlink vorhanden ist, verweist der Matcher anhand der Nummer auf das gespeicherte Suchergebnis der erfassten Gruppe und verwendet dann die Zeichen aus diesem Ergebnis, um eine weitere Suche zu versuchen. Das folgende Beispiel zeigt die Verwendung einer Rückreferenz, um grammatikalische Fehler im Text zu finden: In diesem Beispiel wird ein regulärer Ausdruck verwendet, um einen grammatikalischen Fehler mit einem doppelten Wort zu finden, das unmittelbar im Eingabetext folgt . Dieser reguläre Ausdruck gibt zwei zu erfassende Gruppen an: Nummer 1 – entsprechend und Nummer 2 – entsprechend dem Leerzeichen gefolgt von . Durch die Rückreferenz kann das gespeicherte Ergebnis der Gruppe Nummer 2 erneut aufgerufen werden, sodass der Matcher nach dem zweiten Vorkommen eines Leerzeichens gefolgt von suchen kann , unmittelbar nach dem ersten Vorkommen eines Leerzeichens und . Die Ergebnisse des Matchers sind wie folgt: vaJavaJava(Java( language))(language)(Java)(Java( language))(language)(a)(b)(a)(b)Reguläre Ausdrücke in Java, Teil 2 - 2java RegexDemo "(Java( language)\2)" "The Java language language"(Java( language)\2)languageJava"The Java language language"(Java( language)\2)Java language language(language)language\2languagelanguageRegexDemo
regex = (Java( language)\2)
input = The Java language language
Found [Java language language] starting at 4 and ending at 25

Grenzabgleicher

Manchmal müssen Sie einen Mustervergleich am Anfang einer Zeile, an Wortgrenzen, am Ende eines Textes usw. durchführen. Sie können dies tun, indem Sie einen der Edge-Matcher der Klasse verwenden Pattern, bei denen es sich um reguläre Ausdruckskonstrukte handelt, die an den folgenden Stellen nach Übereinstimmungen suchen:
  • ^: Zeilenanfang;
  • $: Ende der Linie;
  • \b: Wortgrenze;
  • \B: Pseudowortgrenze;
  • \A: Textanfang;
  • \G: Ende des vorherigen Spiels;
  • \Z: Ende des Textes, ohne Berücksichtigung des letzten Zeilentrennzeichens (falls vorhanden);
  • \z: Ende des Textes
Im folgenden Beispiel wird das ^Boundary-Matcher-Metazeichen verwendet, um Zeilen zu finden, die mit beginnen The, gefolgt von null oder mehr Wortzeichen: java RegexDemo "^The\w*" Therefore Das Zeichen ^gibt an, dass die ersten drei Zeichen des Eingabetexts mit aufeinanderfolgenden Musterzeichen T, hund übereinstimmen müssen e, denen eine beliebige Zahl folgen kann von wortbildenden Symbolen. Hier ist das Ergebnis der Ausführung:
regex = ^The\w*
input = Therefore
Found [Therefore] starting at 0 and ending at 8
Was passiert, wenn Sie die Befehlszeile in ändern java RegexDemo "^The\w*" " Therefore"? Es wird keine Übereinstimmung gefunden, da Thereforedem Eingabetext ein Leerzeichen vorangestellt ist.

Übereinstimmungen mit der Länge Null

Wenn Sie mit Edge-Matchern arbeiten, werden Sie manchmal auf Übereinstimmungen mit der Länge Null stoßen. Совпадение нулевой длиныist eine Übereinstimmung, die keine Zeichen enthält. Sie können in leerem Eingabetext, am Anfang des Eingabetexts, nach dem letzten Zeichen des Eingabetexts und zwischen zwei beliebigen Zeichen des Eingabetexts auftreten. Übereinstimmungen mit der Länge Null sind leicht zu erkennen, da sie immer an derselben Position beginnen und enden. Betrachten Sie das folgende Beispiel: java RegExDemo \b\b "Java is" In diesem Beispiel wird nach zwei aufeinanderfolgenden Wortgrenzen gesucht und die Ergebnisse sehen folgendermaßen aus:
regex = \b\b
input = Java is
Found [] starting at 0 and ending at -1
Found [] starting at 4 and ending at 3
Found [] starting at 5 and ending at 4
Found [] starting at 7 and ending at 6
Wir sehen in den Ergebnissen mehrere Übereinstimmungen mit der Länge Null. Die Endpositionen sind hier um eins kleiner als die Startpositionen, da RegexDemoich sie im Quellcode in Listing 1 angegeben habe end() – 1. Reguläre Ausdrücke in Java, Teil 2 - 3

Quantifizierer

Ein Quantor ist ein reguläres Ausdruckskonstrukt, das ein Muster explizit oder implizit einem numerischen Wert zuordnet. Dieser numerische Wert bestimmt, wie oft nach dem Muster gesucht werden soll. Quantifizierer werden in gierig, faul und supergierig unterteilt:
  • Der gierige Quantor ( ?, *oder +) dient dazu, die längste Übereinstimmung zu finden. Kann ich fragen X? ein oder weniger Vorkommen finden X, X*null oder mehr Vorkommen finden X, X+ein oder mehrere Vorkommen finden X, Vorkommen X{n}finden , mindestens (und möglicherweise mehr) Vorkommen finden und mindestens , aber nicht mehr Vorkommen finden .nXX{n,}nXX{n,m}nmX
  • Der Lazy-Quantifizierer ( ??, *?oder +?) dient dazu, die kürzeste Übereinstimmung zu finden. Sie können festlegen X??, dass nach einem oder weniger Vorkommen von X, X*? gesucht werden soll. null oder mehr Vorkommen finden X, X+?ein oder mehrere Vorkommen finden X, Vorkommen X{n}?finden , mindestens (und möglicherweise mehr) Vorkommen finden und mindestens , aber nicht mehr als Vorkommen finden .nXX{n,}?nXX{n,m}?nmX
  • Der supergierige Quantor ( ?+, *+oder ++) ähnelt dem gierigen Quantor, mit der Ausnahme, dass der supergierige Quantor nur einen Versuch unternimmt, die längste Übereinstimmung zu finden, während der gierige Quantor mehrere Versuche unternehmen kann. Kann eingestellt werden X?+, um ein oder weniger Vorkommen zu finden X, X*+null oder mehr Vorkommen zu finden X, X++ein oder mehrere Vorkommen zu finden X, Vorkommen von X{n}+zu finden , mindestens (und möglicherweise mehr) Vorkommen zu finden und mindestens , aber nicht mehr als Vorkommen zu finden .nXX{n,}+nXX{n,m}+ nmX
Das folgende Beispiel veranschaulicht die Verwendung des Greedy-Quantifizierers: java RegexDemo .*ox "fox box pox" Hier sind die Ergebnisse:
regex = .*ox
input = fox box pox
Found [fox box pox] starting at 0 and ending at 10
Der gierige Quantifizierer ( .*) findet die längste Zeichenfolge, die mit endet ox. Es verbraucht den gesamten Eingabetext und führt dann einen Rollback durch, bis festgestellt wird, dass der Eingabetext mit diesen Zeichen endet. Betrachten Sie nun den Lazy-Quantor: java RegexDemo .*?ox "fox box pox" Seine Ergebnisse:
regex = .*?ox
input = fox box pox
Found [fox] starting at 0 and ending at 2
Found [ box] starting at 3 and ending at 6
Found [ pox] starting at 7 and ending at 10
Der Lazy-Quantifier ( .*?) findet die kürzeste Folge von Zeichen, die mit enden ox. Es beginnt mit einer leeren Zeichenfolge und verbraucht nach und nach Zeichen, bis eine Übereinstimmung gefunden wird. Und arbeitet dann weiter, bis der Eingabetext erschöpft ist. Schauen wir uns zum Schluss den supergierigen Quantifizierer an: java RegexDemo .*+ox "fox box pox" Und hier sind seine Ergebnisse:
regex = .*+ox
input = fox box pox
Der besonders gierige Quantifizierer ( .*+) findet keine Übereinstimmungen, da er den gesamten Eingabetext verbraucht und oxam Ende des regulären Ausdrucks nichts mehr zum Abgleichen vorhanden ist. Im Gegensatz zum Greedy-Quantifizierer erfolgt beim Super-Greedy-Quantifizierer kein Rollback.

Übereinstimmungen mit der Länge Null

Wenn Sie mit Quantoren arbeiten, werden Sie manchmal auf Übereinstimmungen mit der Länge Null stoßen. Die Verwendung des folgenden gierigen Quantifizierers führt beispielsweise zu mehreren Übereinstimmungen mit der Länge Null: java RegexDemo a? abaa Die Ergebnisse der Ausführung dieses Beispiels:
regex = a?
input = abaa
Found [a] starting at 0 and ending at 0
Found [] starting at 1 and ending at 0
Found [a] starting at 2 and ending at 2
Found [a] starting at 3 and ending at 3
Found [] starting at 4 and ending at 3
Es gibt fünf Übereinstimmungen in den Ausführungsergebnissen. Obwohl der erste, der dritte und der vierte durchaus zu erwarten sind (sie entsprechen den Positionen von drei Buchstaben ain abaa), könnten der zweite und der fünfte Sie überraschen. Es scheint, als würden sie angeben, was dem Ende des Textes aentspricht , aber in Wirklichkeit ist dies nicht der Fall. bDer reguläre Ausdruck a?sucht nicht bam Ende des Textes. Es sucht nach Anwesenheit oder Abwesenheit a. Wenn a?es nicht findet a, wird es als Übereinstimmung mit der Länge Null gemeldet.

Verschachtelte Flag-Ausdrücke

Matcher gehen von einigen Standardannahmen aus, die beim Kompilieren des regulären Ausdrucks in ein Muster überschrieben werden können. Wir werden dieses Problem später besprechen. Mit einem regulären Ausdruck können Sie alle Standardeinstellungen mithilfe eines verschachtelten Flag-Ausdrucks überschreiben. Dieses reguläre Ausdruckskonstrukt wird als Metazeichen aus Klammern um ein Fragezeichen-Metazeichen ( ?) angegeben, gefolgt von einem lateinischen Kleinbuchstaben. Die Klasse Patternversteht die folgenden verschachtelten Flag-Ausdrücke:
  • (?i): Aktiviert den Mustervergleich ohne Berücksichtigung der Groß-/Kleinschreibung. Wenn Sie beispielsweise einen Befehl verwenden, stimmt java RegexDemo (?i)tree Treehousedie Zeichenfolge Treemit dem Muster überein tree. Die Standardeinstellung ist die Mustersuche unter Berücksichtigung der Groß- und Kleinschreibung.
  • (?x): Ermöglicht die Verwendung von Leerzeichen und Kommentaren, beginnend mit dem Metazeichen innerhalb des Musters #. Der Matcher ignoriert beide. Beispielsweise entspricht java RegexDemo ".at(?x)#match hat, cat, and so on" mattereine Zeichenfolge dem Muster . Standardmäßig sind Leerzeichen und Kommentare nicht zulässig und der Matcher behandelt sie als an der Suche beteiligte Zeichen.mat.at
  • (?s): Aktiviert den Dotall-Modus, in dem das Punkt-Metazeichen zusätzlich zu allen anderen Zeichen mit Zeilentrennzeichen übereinstimmt. java RegexDemo (?s). \nDer Befehl findet beispielsweise ein Newline-Zeichen. Der Standardwert ist das Gegenteil von dotall: Es werden keine Zeilentrennzeichen gefunden. Beispielsweise Java RegexDemo . \nfindet der Befehl kein Zeilenumbruchzeichen.
  • (?m): Aktiviert den Mehrzeilenmodus, bei dem ^der Anfang und $das Ende jeder Zeile abgeglichen werden. Findet beispielsweise java RegexDemo "(?m)^abc$" abc\nabcbeide Sequenzen im Eingabetext abc. Standardmäßig wird der einzeilige Modus verwendet: Entspricht dem Anfang und dem Ende ^des gesamten Eingabetexts . $Gibt beispielsweise java RegexDemo "^abc$" abc\nabceine Antwort zurück, dass es keine Übereinstimmungen gibt.
  • (?u): Aktiviert die Unicode-sensitive Groß-/Kleinschreibung. Wenn dieses Flag in Verbindung mit verwendet wird (?i), ermöglicht es einen Mustervergleich ohne Berücksichtigung der Groß-/Kleinschreibung gemäß dem Unicode-Standard. Die Standardeinstellung besteht darin, nur nach Groß-/Kleinschreibung und US-ASCII-Zeichen zu suchen.
  • (?d): Aktiviert den String-Modus im Unix-Stil, bei dem der Matcher Metazeichen im Kontext .und nur das Zeilentrennzeichen erkennt . Der Standardwert ist der String-Modus im Nicht-Unix-Stil: Der Matcher erkennt im Kontext der oben genannten Metazeichen alle Zeilentrennzeichen.^$\n
Verschachtelte Flag-Ausdrücke ähneln erfassten Gruppen, da ihre Zeichen von Metazeichen in Klammern umgeben sind. Im Gegensatz zu erfassten Gruppen sind verschachtelte Flag-Ausdrücke ein Beispiel für nicht erfasste Gruppen, bei denen es sich um ein reguläres Ausdruckskonstrukt handelt, das keine Textzeichen erfasst. Sie sind als Zeichenfolgen definiert, die von Metazeichen oder Klammern umgeben sind.
Angeben mehrerer verschachtelter Flag-Ausdrücke
Es ist möglich, mehrere verschachtelte Flag-Ausdrücke in einem regulären Ausdruck anzugeben, indem Sie sie entweder nebeneinander platzieren ( (?m)(?i))) oder die Buchstaben, die sie definieren, nacheinander platzieren ( (?mi)).

Abschluss

Wie Sie wahrscheinlich inzwischen erkannt haben, sind reguläre Ausdrücke äußerst nützlich und werden noch nützlicher, je mehr Sie die Nuancen ihrer Syntax beherrschen. Bisher habe ich Ihnen die Grundlagen regulärer Ausdrücke und der Pattern. In Teil 2 werfen wir einen tieferen Blick auf die Regex-API und erkunden die Methoden von Pattern, Matcherund PatternSyntaxException. Außerdem zeige ich Ihnen zwei praktische Anwendungen der Regex-API, die Sie sofort in Ihren Programmen nutzen können. Reguläre Ausdrücke in Java, Teil 3 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