Reguläre Ausdrücke sind eine äußerst vielseitige Methode, um Strings mit Musterabgleich zu prüfen. Dafür nutzen sie eine eigens für diesen Zweck entwickelte domänenspezifische Sprache (DSL).
Wie einige andere Programmiersprachen versucht Julia gar nicht erst, eine eigene Regex-Bibliothek zu implementieren. Stattdessen greift es auf die weit verbreitete Bibliothek PCRE2 zurück und bietet damit eine Regex-Syntax, die identisch ist mit (zum Beispiel) Gleam und sehr ähnlich zu JavaScript.
Dieser Julia-Lehrplan geht davon aus, dass du bereits mit der grundlegenden Regex-Syntax vertraut bist. Wir konzentrieren uns ausschließlich auf die Julia-spezifischen Features.
Einige Ressourcen zum Auffrischen deiner Regex-Kenntnisse sind unten aufgeführt.
Julias Schnittstelle zu regulären Ausdrücken wird im Handbuch beschrieben.
Ein regulärer Ausdruck in Julia ist einfach ein String, dem vor dem öffnenden " ein r vorangestellt wird.
Die gesamte grundlegende Funktionalität ist Teil der Standardbibliothek.
Tatsächlich sind viele der Funktionen, die bereits im Konzept Strings behandelt wurden, standardmäßig für Regex-Suchen ausgelegt, zum Beispiel occursin().
julia> re = r"test$"
r"test$"
julia> typeof(re)
Regex
# Does a string end with "test"?
julia> occursin(re, "this is a test")
true
julia> occursin(re, "these are tests")
false
Nach dem schließenden Anführungszeichen können Modifiziererzeichen stehen, etwa i für eine Übereinstimmung ohne Beachtung der Groß- und Kleinschreibung.
julia> occursin(r"test", "Testing")
false
julia> occursin(r"test"i, "Testing")
true
Häufig wollen wir wissen, was übereinstimmt. Dazu fügst du Capture-Gruppen in runden Klammern in den Regex ein und verwendest anschließend die Funktion match().
julia> m = match(r"(\d+g) .* (\d+ml)", "dissolve 25g sugar in 200ml water")
RegexMatch("25g sugar in 200ml", 1="25g", 2="200ml")
julia> m.captures
2-element Vector{Union{Nothing, SubString{String}}}:
"25g"
"200ml"
# how many matches?
julia> length(m.captures)
2
# what matched?
julia> m[1], m[2]
("25g", "200ml")
# Starting positions of the matches (character index)
julia> m.offsets
2-element Vector{Int64}:
10
23
Natürlich können Übereinstimmungen fehlschlagen.
Das Ergebnis ist dann der spezielle Wert Nothing statt eines RegexMatch. Sei also darauf vorbereitet, das zu prüfen.
# failed match
m = match(r"(not here)", "dissolve 25g sugar in 200ml water")
julia> typeof(m)
Nothing
julia> isnothing(m)
true
Obwohl match standardmäßig am Anfang des Strings beginnt, kannst du auch einen Offset n angeben, um die ersten n Zeichen zu ignorieren.
# capture first match
julia> m = match(r"(\wat)", "cat, sat, mat")
RegexMatch("cat", 1="cat")
# ignore first 5 characters, then match
julia> m = match(r"(\wat)", "cat, sat, mat", 5)
RegexMatch("sat", 1="sat")
In Julia findet match() nur die erste Übereinstimmung im Ziel-String. Einen globalen Modifikator wie in manchen anderen Sprachen gibt es nicht.
Stattdessen gibt es eachmatch(), das einen Iterator über die Übereinstimmungen zurückgibt.
Dieser wird erst bei Bedarf ausgewertet, du musst ihn also möglicherweise in das gewünschte Format umwandeln.
julia> matches = eachmatch(r"(\wat)", "cat, sat, mat")
Base.RegexMatchIterator{String}(r"(\wat)", "cat, sat, mat", false)
# convert to vector
julia> collect(matches)
3-element Vector{RegexMatch}:
RegexMatch("cat", 1="cat")
RegexMatch("sat", 1="sat")
RegexMatch("mat", 1="mat")
# convert with comprehension
julia> [m.match for m in matches]
3-element Vector{SubString{String}}:
"cat"
"sat"
"mat"
# broadcast an anonymous function
julia> (m -> m.match).(matches)
3-element Vector{SubString{String}}:
"cat"
"sat"
"mat"
Ein häufiger Grund für den Einsatz eines Regex ist es, die Übereinstimmung durch einen anderen String zu ersetzen.
Die Funktion replace() wurde im Konzept Strings behandelt, wo String-Literale zur Suche dienten.
Dieselbe Funktion kann die volle Stärke des Regex-Matchings nutzen.
julia> replace("some string", r"[aeiou]" => "*")
"s*m* str*ng"
julia> replace("first second", r"(\w+) (?<agroup>\w+)" => s"\g<agroup> \1")
"second first"
Das zweite Beispiel oben zeigt, wie sowohl nummerierte als auch benannte Capture-Gruppen in der Ersetzung verwendet werden können, und zwar innerhalb eines s" "-Strings.
Weitere Details findest du im Handbuch: Dies ist ein Thema, das die meisten Programmierer immer wieder zur Dokumentation zurückzwingt!
Du wurdest als Spezialist für reguläre Ausdrücke von einem Unternehmen eingestellt, das einen Chatbot entwickelt.
Das Unternehmen steckt in einer sehr frühen Entwicklungsphase. Deine Aufgabe ist es deshalb, mit regulären Ausdrücken die Fähigkeit des Chatbots zu verbessern, natürliche Sprache zu verstehen und zu erzeugen.
Zu Lernzwecken löse diese Aufgaben bitte mit regulären Ausdrücken.
Wir wissen, dass manchmal auch andere Lösungen möglich sind (und sogar performanter sein können!)
Der Chatbot ist nicht nur schlau, sondern auch ein loyaler Assistent.
Um den Chatbot etwas zu fragen, muss der Nutzer das Wort „Chatbot“ an der ersten Position des Befehls sagen.
Es spielt keine Rolle, ob das Schlüsselwort in Groß- oder Kleinbuchstaben geschrieben ist. Wichtig ist hier die Position des Wortes.
Implementiere die Funktion is_valid_command(), die dem Chatbot hilft zu erkennen, wann der Nutzer einen Befehl gibt.
julia> is_valid_command("Chatbot, play a song from the 80's.")
True
julia> is_valid_command("Hey Chatbot, where is the closest pharmacy?")
False
julia> is_valid_command("CHATBOT, do you have a solution for this challenge?")
True
Der Chatbot hat Schwierigkeiten zu verstehen, wie Menschen Emojis verwenden, um ihre Gefühle auszudrücken.
Wenn der Chatbot Nachrichten von Nutzern empfängt, wird jedes Emoji als „emoji“ gefolgt von seiner id-Nummer dargestellt.
Implementiere die Methode remove_emoji(), die einen String entgegennimmt und die gesamte Emoji-Verschlüsselung aus der Nachricht entfernt.
Zeilen, die keinen Emoji-Text enthalten, werden unverändert zurückgegeben.
Entferne einfach den Emoji-String. Versuche nicht, die Leerzeichen anzupassen.
julia> remove_emoji("I love playing videogames emoji3465 it's one of my hobbies")
"I love playing videogames it's one of my hobbies"
Da die Funktionen des Chatbots in einer mobilen App heruntergeladen werden können, wird erwartet, dass der Nutzer während der Unterhaltung eine Telefonnummer eingibt.
Das Problem ist, dass der Chatbot nur eine Nummer mit einem bestimmten Format lesen und validieren kann.
Ist die Nummer gültig (entspricht sie also der Zeichenfolge, die der reguläre Ausdruck beschreibt), antwortet der Chatbot mit einer Nachricht, in der er sich beim Nutzer bedankt und die Nummer bestätigt. Ist die Nummer ungültig, teilt die Funktion dem Nutzer mit, dass die Telefonnummer nicht gültig ist.
Das erwartete Format ist: (+##) ###-###-###
julia> check_phone_number("(+34) 659-771-594")
"Thanks! You can now download me to your phone."
julia> check_phone_number("659-771-594")
"Oops, it seems like I can't reach out to 659-771-594"
Der Chatbot ist eine wirklich neugierige Software. Obwohl er im Internet zu einem bestimmten Thema suchen kann, fragt er Nutzer gern nach coolen Websites oder URLs, um relevante Informationen zu finden.
Beispiel für eine Unterhaltung:
Implementiere die Funktion getURL(), die ein Array zurückgibt, das nur den Link jeder Website enthält.
julia> getURL("I learned a lot from exercism.org")
["exercism.org"]
Um Daten von allen Personen zu speichern, mit denen er sich unterhalten hat, kann der Chatbot den vollständigen Namen im Stil „smith, john“ aus dem Profil des Nutzers auslesen.
So soll unser Chatbot richtig höflich wirken und einen guten Eindruck machen.
Schreibe die Funktion nice_to_meet_you(), die einen String mit dem vollständigen Namen des Nutzers entgegennimmt und den String „Nice to meet you, John Smith“ zurückgibt.
julia> str = "Smith, John"
julia> nice_to_meet_you(str)
"Nice to meet you, John Smith"
Melde dich bei Exercism an, um Julia mit 35 Konzepte128 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.