Dies ist Teil zwei einer zweiteiligen Serie von Tutorials zu regulären Ausdrücken in Go. In Teil 1 haben wir gelernt, was reguläre Ausdrücke sind, wie man sie in Go ausdrückt, und die Grundlagen der Verwendung der Go-regulären Ausdrücke-Bibliothek, um Text mit regulären Ausdrucksmustern abzugleichen.
In Teil zwei werden wir uns darauf konzentrieren, die regexp-Bibliothek in vollem Umfang zu nutzen. Dazu gehören das Erstellen regulärer Ausdrücke, das Finden einer oder mehrerer Übereinstimmungen im Text, das Ersetzen regulärer Ausdrücke, das Gruppieren von Submatches und der Umgang mit neuen Zeilen.
Die regexp-Bibliothek bietet umfassende Unterstützung für reguläre Ausdrücke sowie die Möglichkeit, Muster für eine effizientere Ausführung zu kompilieren, wenn dasselbe Muster für mehrere Texte verwendet wird. Sie können auch Übereinstimmungsindizes finden, Übereinstimmungen ersetzen und Gruppen verwenden. Lass uns eintauchen.
Es gibt zwei Methoden zum Kompilieren von Ausdrücken: Kompilieren()
und MustCompile ()
. Kompilieren()
gibt einen Fehler zurück, wenn das angegebene Muster ungültig ist. MustCompile ()
wird in Panik geraten. Die Kompilierung wird empfohlen, wenn Sie Wert auf die Leistung legen und die gleiche Regex mehrmals verwenden möchten. Lass uns unser ändern Spiel()
Helferfunktion, um eine kompilierte Regex aufzunehmen. Beachten Sie, dass keine Überprüfung auf Fehler erforderlich ist, da der kompilierte reguläre Ausdruck gültig sein muss.
func match (r * regexp.Regexp, Textzeichenfolge) matched: = r.MatchString (text) bei Übereinstimmung fmt.Println ("√", r.String (), ":", text) else fmt. Println ("X", r.String (), ":", Text)
So kompilieren und verwenden Sie dieselbe kompilierte Regex mehrmals:
func main () es: = '(\ bcats? \ b) | (\ bdogs? \ b) | (\ brats? \ b)' e: = regexp.MustCompile (es) passt (e) "Es regnet Hunde und Katzen ") stimmen überein (e," Der Katalog ist fertig. Es ist Hotdog-Zeit! ") entspricht (e," Es ist ein Hund frisst Hundewelt. ") Ausgabe: √ (\ bcats? \ b) | (\ bdogs? \ b) | (\ brats? \ b): Es regnet Hunde und Katzen X (\ bcats? \ b) | (\ bdogs? \ b) | (\ brats? \ b): Der Katalog ist fertig. Es ist Hotdog-Zeit! √ (\ bcats? \ B) | (\ bdogs? \ B) | (\ brats? \ B): Es ist eine Hundefutterwelt.
Das Regexp-Objekt hat eine Menge von FindXXX ()
Methoden. Einige geben den ersten Treffer zurück, andere alle Treffer und wieder andere einen oder mehrere Indizes. Interessanterweise stimmen die Namen aller 16 Funktionsmethoden mit der folgenden Regex überein: Find (All) (String) (Submatch) (Index)?
Wenn "Alle" vorhanden ist, werden alle Übereinstimmungen gegen die äußerste linke zurückgegeben. Wenn 'String' vorhanden ist, handelt es sich bei dem Zieltext und den Rückgabewerten um Zeichenfolgen im Vergleich zu Byte-Arrays. Wenn "Submatch" vorhanden ist, werden Submatches (Gruppen) gegenüber einfachen Übereinstimmungen zurückgegeben. Wenn "Index" vorhanden ist, werden die Indizes im Zieltext gegen die tatsächlichen Übereinstimmungen zurückgegeben.
Nehmen wir eine der komplexeren Funktionen und verwenden Sie die FindAllStringSubmatch ()
Methode. Es braucht einen String und eine Nummer n
. Ob n
Ist -1, werden alle übereinstimmenden Indizes zurückgegeben. Wenn n eine nicht negative ganze Zahl ist, werden die n am weitesten links liegenden Übereinstimmungen zurückgegeben. Das Ergebnis ist ein Slice von String-Slices.
Das Ergebnis jedes Submatches ist die vollständige Übereinstimmung, gefolgt von der erfassten Gruppe. Stellen Sie sich beispielsweise eine Liste mit Namen vor, bei denen einige Titel wie "Mr.", "Mrs." oder "Dr." tragen. Hier ist ein Regex, der den Titel als Submatch und dann den Rest des Namens nach einem Leerzeichen erfasst: \ b (Herr \. | Frau \. | Dr \.). *.
.
func main () re: = regexp.MustCompile ('\ b (Herr \. | Frau \. | Dr \.). *') fmt.Println (re.FindAllStringSubmatch ("Dr. Dolittle", -1)) fmt.Println (re.FindAllStringSubmatch ('Mrs. Doubtfire Mr. Anderson', -1)) Ausgabe: [[Dr. Dolittle Dr.]] [[Frau Doubtfire Mrs.] [Herr Anderson Mr.]]
Wie Sie in der Ausgabe sehen können, wird zuerst die vollständige Übereinstimmung und dann nur der Titel erfasst. Für jede Zeile wird die Suche zurückgesetzt.
Das Finden von Übereinstimmungen ist großartig, aber häufig müssen Sie das Spiel durch etwas anderes ersetzen. Das Regexp-Objekt hat mehrere Ersetzen Sie XXX ()
Methoden wie üblich für den Umgang mit Strings vs. Byte-Arrays und literalen Ersetzungen vs. Erweiterungen. In dem großen Buch 1984 von George Orwell sind die Parolen der Partei in die weiße Pyramide des Wahrheitsministeriums eingeschrieben:
Ich habe einen kleinen Aufsatz über den Preis der Freiheit gefunden, der einige dieser Begriffe verwendet. Lassen Sie uns ein Snippet davon gemäß dem Party-Doublespeak mit Go-Regex korrigieren. Beachten Sie, dass einige der Zielwörter für die Ersetzung andere Großschreibung verwenden. Die Lösung besteht darin, das Kennzeichen ohne Berücksichtigung der Groß- und Kleinschreibung hinzuzufügen (ich?)
am Anfang der Regex.
Da die Übersetzung je nach Fall unterschiedlich ist, benötigen wir einen differenzierteren Ansatz als einen wörtlichen Ersatz. Glücklicherweise (oder von Entwurf) hat das Regexp-Objekt eine Ersetzungsmethode, die eine Funktion akzeptiert, die es verwendet, um den tatsächlichen Ersetzungsvorgang durchzuführen. Definieren Sie unsere Ersetzungsfunktion, die die Übersetzung mit dem richtigen Fall zurückgibt.
func replacer (s string) string d: = map [string] string "krieg": "frieden", "krieg": "fried", "krieg": "frieden", "freiheit": "sklaverei", " FREIHEIT ":" Sklaverei "," Freiheit ":" Sklaverei "," Ignoranz ":" Stärke "," Ignoranz ":" STÄRKE "," Ignoranz ":" Stärke ", r, ok: = d [s] if ok return r else return s
Jetzt können wir den tatsächlichen Ersatz durchführen:
func main () text: = 'DER PREIS DER FREIHEIT: Amerikaner im Krieg Amerikaner sind in den Krieg gegangen, um ihre Unabhängigkeit zu gewinnen, ihre nationalen Grenzen zu erweitern, ihre Freiheiten zu definieren und ihre Interessen auf der ganzen Welt zu verteidigen.' expr: = '(? i) (Krieg | Freiheit | Unwissenheit)' r: = regexp.MustCompile (expr) Ergebnis: = r.ReplaceAllStringFunc (Text, Ersetzer) fmt.Println (Ergebnis) Americans at Peace Die Amerikaner sind zum Frieden gegangen, um ihre Unabhängigkeit zu erreichen, ihre nationalen Grenzen zu erweitern, ihre Sklavenhändler zu definieren und ihre Interessen auf der ganzen Welt zu verteidigen.
Der Output ist etwas inkohärent, was das Markenzeichen guter Propaganda ist.
Wir haben zuvor gesehen, wie man Gruppierungen mit Submatches verwendet. Es ist jedoch manchmal schwierig, mit mehreren Submatches umzugehen. Benannte Gruppen können hier sehr helfen. So benennen Sie Ihre Submatch-Gruppen und füllen ein Wörterbuch für den einfachen Zugriff nach Namen auf:
func main () e: = '(? P\ w +) (? P .+ ) (? P \ w +) 'r: = regexp.MustCompile (e) Namen: = r.SubexpNames () fullNames: = [] Zeichenfolge ' John F. Kennedy ',' Michael Jordan ' für _, fullName: = range fullNames Ergebnis : = r.FindAllStringSubmatch (fullName, -1) m: = map [Zeichenfolge] Zeichenfolge für i, n: = Bereichsergebnis [0] m [Namen [i]] = n fmt.Println ("Vorname : ", m [" erster "]) fmt.Println (" mittlerer_name: ", m [" mittlerer "]) fmt.Println (" Nachname: ", m [" letzter "]) fmt.Println () Ausgabe: Vorname: John Vorname: F. Nachname: Kennedy Vorname: Michael Vorname: Nachname: Jordan
Wenn Sie sich erinnern, sagte ich, dass das Punkt-Sonderzeichen mit jedem Zeichen übereinstimmt. Ich habe gelogen. Es passt nicht zum Newline (\ n
) Zeichen standardmäßig. Das bedeutet, dass Ihre Übereinstimmungen keine Linien kreuzen, sofern Sie sie nicht explizit mit dem speziellen Flag angeben (? s)
dass Sie an den Anfang Ihrer Regex hinzufügen können. Hier ist ein Beispiel mit und ohne Flagge.
func main () text: = "1111 \ n2222" Ausdruck: = [] Zeichenfolge ". *", "(? s). *" für _, e: = Bereichsausdruck r: = regexp.MustCompile ( e) result: = r.FindString (text) result = strings.Replace (Ergebnis, "\ n", '\ n', -1) fmt.Println (e, ":", result) fmt.Println () Ausgabe:. *: 1111 (? S). *: 1111 \ n2222
Eine weitere Überlegung ist, ob das behandelt werden soll ^
und $
Sonderzeichen als Anfang und Ende des gesamten Textes (Standardeinstellung) oder als Anfang und Ende jeder Zeile mit (? m)
Flagge.
Reguläre Ausdrücke sind ein leistungsfähiges Werkzeug, wenn Sie mit semi-strukturiertem Text arbeiten. Sie können sie verwenden, um die Texteingabe zu überprüfen, sie zu bereinigen, umzuwandeln, zu normalisieren und generell mit einer großen Vielfalt von Unterschieden mit einer prägnanten Syntax umzugehen.
Go bietet eine Bibliothek mit einer benutzerfreundlichen Schnittstelle, die aus einem Regexp-Objekt mit vielen Methoden besteht. Probieren Sie es aus, aber passen Sie auf die Fallstricke auf.