Das Paket regexp bietet Unterstützung für reguläre Ausdrücke in Go.
Die Syntax der akzeptierten regulären Ausdrücke entspricht der allgemeinen Syntax, die auch Perl, Python und andere Sprachen verwenden.
Sowohl die Suchmuster als auch die Eingabetexte werden als UTF-8 interpretiert.
Wenn du Backticks (`) verwendest, um Strings zu erzeugen, haben Backslashes (\) keine besondere Bedeutung und markieren nicht den Anfang von Sonderzeichen wie Tabs \t oder Zeilenumbrüchen \n:
"\t\n" // regular string literal with 2 characters: a tab and a newline
`\t\n`// raw string literal with 4 characters: two backslashes, a 't', and an 'n'
Deshalb ist es sinnvoll, für reguläre Ausdrücke Backticks zu verwenden, denn so müssen wir keine Backslashes escapen:
"\\" // string with a single backslash
`\\` // string with 2 backslashes
RegExp
Um einen regulären Ausdruck zu verwenden, müssen wir zuerst das Muster als String kompilieren.
Kompilieren bedeutet hier, dass das Muster des regulären Ausdrucks als String genommen und in eine interne Darstellung umgewandelt wird, mit der sich leichter arbeiten lässt.
Wir müssen jedes Muster nur einmal kompilieren; danach können wir die kompilierte Version des regulären Ausdrucks beliebig oft verwenden.
Der Typ regexp.Regexp repräsentiert einen kompilierten regulären Ausdruck.
Wir können ein Muster als String mit der Funktion regexp.Compile zu einem regexp.Regexp kompilieren.
Diese Funktion gibt nil und einen Fehler zurück, wenn das Kompilieren fehlgeschlagen ist:
re, err := regexp.Compile(`(a|b)+`)
fmt.Println(re, err) // => (a|b)+ <nil>
re, err = regexp.Compile(`a|b)+`)
fmt.Println(re, err) // => <nil> error parsing regexp: unexpected ): `a|b)+`
Die Funktion MustCompile ist eine praktische Alternative zu Compile:
re = regexp.MustCompile(`[a-z]+\d*`)
Bei dieser Funktion musst du keinen Fehler behandeln.
MustCompile solltest du nur verwenden, wenn du sicher weißt, dass das Muster kompiliert, denn andernfalls stürzt das Programm mit einer Panic ab.
Es gibt 16 Methoden von Regexp, die einen regulären Ausdruck abgleichen und den gefundenen Text identifizieren.
Ihre Namen folgen diesem regulären Ausdruck:
Find(All)?(String)?(Submatch)?(Index)?
All vorhanden ist, findet die Methode aufeinanderfolgende, nicht überlappende Treffer des gesamten Ausdrucks.String vorhanden ist, ist das Argument ein String, andernfalls ist es ein Slice von Bytes; die Rückgabewerte werden entsprechend angepasst.Submatch vorhanden ist, ist der Rückgabewert ein Slice, der die aufeinanderfolgenden Submatches des Ausdrucks angibt.Index vorhanden ist, werden Treffer und Submatches durch Byte-Index-Paare innerhalb des Eingabe-Strings angegeben.Außerdem gibt es Methoden zum:
Insgesamt definiert das Paket regexp mehr als 40 Funktionen und Methoden.
Wir zeigen unten die Verwendung einiger Methoden.
Weitere Einzelheiten zu diesen und anderen Funktionen findest du in der API-Dokumentation.
MatchString
Die Methode MatchString gibt an, ob ein String einen Treffer des regulären Ausdrucks enthält.
re = regexp.MustCompile(`[a-z]+\d*`)
b = re.MatchString("[a12]") // => true
b = re.MatchString("12abc34(ef)") // => true
b = re.MatchString(" abc!") // => true
b = re.MatchString("123 456") // => false
FindString
Die Methode FindString gibt einen String mit dem Text des am weitesten links stehenden Treffers des regulären Ausdrucks zurück.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.FindString("[a12]") // => "a12"
s = re.FindString("12abc34(ef)") // => "abc34"
s = re.FindString(" abc!") // => "abc"
s = re.FindString("123 456") // => ""
FindStringSubmatch
Die Methode FindStringSubmatch gibt ein Slice von Strings zurück, das den Text des am weitesten links stehenden Treffers des regulären Ausdrucks und, falls vorhanden, die Treffer seiner Unterausdrücke enthält.
Damit lassen sich die Strings identifizieren, die zu Capturing-Gruppen passen.
Ein Rückgabewert von nil zeigt an, dass es keinen Treffer gibt.
re = regexp.MustCompile(`[a-z]+(\d*)`)
sl = re.FindStringSubmatch("[a12]") // => []string{"a12","12"}
sl = re.FindStringSubmatch("12abc34(ef)") // => []string{"abc34","34"}
sl = re.FindStringSubmatch(" abc!") // => []string{"abc",""}
sl = re.FindStringSubmatch("123 456") // => <nil>
ReplaceAllString
Die Methode re.ReplaceAllString(src,repl) gibt eine Kopie von src zurück und ersetzt dabei Treffer des regulären Ausdrucks re durch den Ersatz-String repl.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.ReplaceAllString("[a12]", "X") // => "[X]"
s = re.ReplaceAllString("12abc34(ef)", "X") // => "12X(X)"
s = re.ReplaceAllString(" abc!", "X") // => " X!"
s = re.ReplaceAllString("123 456", "X") // => "123 456"
Split
Die Methode re.Split(s,n) zerlegt einen Text s in Teilstrings, die durch den Ausdruck getrennt sind, und gibt ein Slice der Teilstrings zwischen diesen Treffern zurück.
Die Anzahl n bestimmt die maximale Anzahl der zurückgegebenen Teilstrings.
Wenn n<0, gibt die Methode alle Teilstrings zurück.
re = regexp.MustCompile(`[a-z]+\d*`)
sl = re.Split("[a12]", -1) // => []string{"[","]"}
sl = re.Split("12abc34(ef)", 2) // => []string{"12","(ef)"}
sl = re.Split(" abc!", -1) // => []string{" ","!"}
sl = re.Split("123 456", -1) // => []string{"123 456"}
In dieser Übung geht es um das Parsen von Logdateien.
Nach einer kürzlichen Sicherheitsüberprüfung wurdest du gebeten, die archivierten Logdateien der Organisation aufzuräumen.
Alle Strings, die an die Funktionen übergeben werden, sind garantiert nicht null und haben keine führenden oder abschließenden Leerzeichen.
Du brauchst einen Überblick darüber, wie viele Logzeilen in deinem Archiv nicht den aktuellen Standards entsprechen. Du bist der Meinung, dass ein einfacher Test zeigt, ob eine Logzeile gültig ist. Um als gültig zu gelten, muss eine Zeile mit einem der folgenden Strings beginnen:
Implementiere die Funktion IsValidLine, sodass sie false zurückgibt, wenn ein String nicht gültig ist, andernfalls true.
IsValidLine("[ERR] A good error here")
// => true
IsValidLine("Any old [ERR] text")
// => false
IsValidLine("[BOB] Any old text")
// => false
Ein neues Team ist der Organisation beigetreten, und du stellst fest, dass seine Logdateien ein seltsames Trennzeichen für „Felder“ verwenden. Statt etwas Vernünftigem wie einem Doppelpunkt „:“ verwenden sie einen String wie „<--->“ oder „<=>“ (weil es hübscher aussieht), und zwar jeden String, dessen erstes Zeichen „<“ und dessen letztes Zeichen „>“ ist und der dazwischen eine beliebige Kombination der folgenden Zeichen enthält: „~“, „*“, „=“ und „-“.
Implementiere die Funktion SplitLogLine, die eine Zeile entgegennimmt und ein Array von Strings zurückgibt, von denen jeder ein Feld enthält.
SplitLogLine("section 1<*>section 2<~~~>section 3")
// => []string{"section 1", "section 2", "section 3"},
password in zitiertem Text enthaltenDas Team muss über Verweise auf Passwörter in zitiertem Text Bescheid wissen, damit sie manuell überprüft werden können.
Implementiere die Funktion CountQuotedPasswords, um einen Hinweis auf den wahrscheinlichen Umfang der manuellen Arbeit zu geben.
Identifiziere Logzeilen, in denen der String „password“, der in beliebiger Groß- und Kleinschreibung vorkommen kann, von Anführungszeichen umgeben ist. Du solltest berücksichtigen, dass zwischen den Anführungszeichen vor und nach „password“ zusätzlicher Inhalt stehen kann. Jede Zeile enthält höchstens zwei Anführungszeichen.
Zeilen, die an die Routine übergeben werden, können gültig oder ungültig sein, wie in Aufgabe 1 definiert. Wir verarbeiten sie auf die gleiche Weise, unabhängig davon, ob sie gültig sind.
lines := []string{
`[INF] passWord`, // contains 'password' but not surrounded by quotation marks
`"passWord"`, // count this one
`[INF] User saw error message "Unexpected Error" on page load.`, // does not contain 'password'
`[INF] The message "Please reset your password" was ignored by the user`, // count this one
}
// => 2
Du hast festgestellt, dass eine vorgelagerte Verarbeitung der Logs den Text „end-of-line“, gefolgt von einer Zeilennummer (ohne dazwischenliegendes Leerzeichen), in den Logs verstreut.
Implementiere die Funktion RemoveEndOfLineText, die einen String entgegennimmt, den end-of-line-Text entfernt und einen „sauberen“ String zurückgibt.
Zeilen, die keinen end-of-line-Text enthalten, sollen unverändert zurückgegeben werden.
Entferne einfach den end-of-line-String. Versuche nicht, die Leerzeichen anzupassen.
RemoveEndOfLineText("[INF] end-of-line23033 Network Failure end-of-line27")
// => "[INF] Network Failure "
Dir ist aufgefallen, dass einige der Logzeilen Sätze enthalten, die sich auf Benutzer beziehen.
Diese Sätze enthalten immer den String "User", gefolgt von einem oder mehreren Leerzeichen und dann einem Benutzernamen.
Du beschließt, solche Zeilen zu markieren.
Implementiere eine Funktion TagWithUserName, die Logzeilen verarbeitet:
"User " nicht enthalten, bleiben unverändert."User " enthalten, stellst du der Zeile [USR] gefolgt vom Benutzernamen voran.Zum Beispiel:
result := TagWithUserName([]string{
"[WRN] User James123 has exceeded storage space.",
"[WRN] Host down. User Michelle4 lost connection.",
"[INF] Users can login again after 23:00.",
"[DBG] We need to check that user names are at least 6 chars long.",
})
// => []string {
// "[USR] James123 [WRN] User James123 has exceeded storage space.",
// "[USR] Michelle4 [WRN] Host down. User Michelle4 lost connection.",
// "[INF] Users can login again after 23:00.",
// "[DBG] We need to check that user names are at least 6 chars long."
// }
Du kannst davon ausgehen, dass:
"User " gibt.Melde dich bei Exercism an, um Go mit 34 Konzepte165 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.