Tracks
/
jq
jq
/
Übungen
/
Regulärer Chatbot
Regulärer Chatbot

Regulärer Chatbot

Lernübung

Einführung

Reguläre Ausdrücke

Reguläre Ausdrücke (Regexes) sind Zeichenfolgen, die ein Suchmuster in einem Text beschreiben.

Die Syntax regulärer Ausdrücke zu lernen, geht über den Rahmen dieses Themas hinaus. Wir konzentrieren uns auf die Ausdrücke, die jq bereitstellt, um Regexes zu nutzen.

Regex-Variante

Verschiedene Werkzeuge implementieren unterschiedliche Versionen regulärer Ausdrücke. jq verwendet die Regex-Bibliothek Oniguruma, die weitgehend mit den regulären Ausdrücken von Perl v5.8 kompatibel ist.

Die konkrete Syntax, die jq verwendet, findest du im Oniguruma-Repository auf GitHub.

Caution

jq hat keine besondere Syntax für reguläre Ausdrücke. Sie werden einfach als Strings ausgedrückt. Das bedeutet, dass alle Backslashes im regulären Ausdruck im String escapt werden müssen.

Zum Beispiel muss die Zeichenklasse für Ziffern (\d) als "\\d" geschrieben werden.

Regex-Funktionen

Reguläre Ausdrücke in jq sind auf eine Reihe von Filtern beschränkt.

Einfaches Abgleichen

Wenn du wissen möchtest, ob ein String zu einem Muster passt, verwendest du den test-Filter.

STRING | test(REGEX)
STRING | test(REGEX; FLAGS)
STRING | test([REGEX, FLAGS])

Dieser Filter gibt ein boolesches Ergebnis aus.

"Hello World!" | test("W")    # => true
"Goodbye Mars" | test("W")    # => false
Informationen über den Treffer

Wenn du den Teilstring extrahieren möchtest, der tatsächlich zum Muster gepasst hat, verwendest du den match-Filter.

STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])

Dieser Filter gibt aus:

  • nichts, wenn es keinen Treffer gab, oder
  • ein Objekt mit verschiedenen Eigenschaften, wenn es einen Treffer gab.

Dieses Beispiel sucht mit der Backref-Syntax \1 nach zwei aufeinanderfolgenden gleichen Vokalen.

"Hello World!" | match("([aeiou])\\1")
# => empty

"Goodbye Mars" | match("([aeiou])\\1")
# => {
#      "offset": 1,
#      "length": 2,
#      "string": "oo",
#      "captures": [
#        {
#          "offset": 1,
#          "length": 1,
#          "string": "o",
#          "name": null
#        }
#      ]
#    }

Der match-Filter gibt für jeden Treffer ein Objekt zurück. Dieses Beispiel zeigt das Flag "g" in Aktion, um alle Vokale zu finden.

"Goodbye Mars" | match("[aeiou]"; "g")
# => { "offset": 1, "length": 1, "string": "o", "captures": [] }
#    { "offset": 2, "length": 1, "string": "o", "captures": [] }
#    { "offset": 6, "length": 1, "string": "e", "captures": [] }
#    { "offset": 9, "length": 1, "string": "a", "captures": [] }
Erfasste Teilstrings

Ähnlich wie der match-Filter gibt der capture-Filter ein Objekt zurück, wenn es einen Treffer gab.

STRING | capture(REGEX)
STRING | capture(REGEX; FLAGS)
STRING | capture([REGEX, FLAGS])

Das zurückgegebene Objekt ist eine Zuordnung der benannten Captures.

"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
#      "project": "JIRAISSUE",
#      "issue_num": "1234"
#    }
Nur die Teilstrings

Der scan-Filter ähnelt match mit dem Flag "g".

STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)

scan gibt einen Stream von Teilstrings aus.

"Goodbye Mars" | scan("[aeiou]")
# => "o"
#    "o"
#    "e"
#    "a"

Verwende den Array-Konstruktor [...], um die Teilstrings zu erfassen.

"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]
Einen String aufteilen

Wenn du die Teile des Strings kennst, die du behalten möchtest, verwende match oder scan. Wenn du die Teile kennst, die du verwerfen möchtest, verwende split.

STRING | split(REGEX; FLAGS)
Caution

Der split-Filter mit einem Argument (1-arity) behandelt sein Argument als festen String.

Um mit split einen regulären Ausdruck zu verwenden, musst du das zweite Argument angeben; eine leere Zeichenkette ist in Ordnung.

Ein Beispiel, das einen String an beliebigem Leerraum aufteilt.

"first   second           third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
Ersetzungen

Die Filter sub und gsub können den Eingabe-String umwandeln, indem sie die übereinstimmenden Teile der Eingabe durch einen Ersatz-String ersetzen.

Um nur den ersten Treffer zu ersetzen, verwende sub. Um alle Treffer zu ersetzen, verwende gsub.

STRING | sub(REGEX; REPLACEMENT)
STRING | sub(REGEX; REPLACEMENT; FLAGS)
STRING | gsub(REGEX; REPLACEMENT)
STRING | gsub(REGEX; REPLACEMENT; FLAGS)
"Goodnight kittens. Goodnight mittens." | sub("night"; " morning")
# => "Good morning kittens. Goodnight mittens."

"Goodnight kittens. Goodnight mittens." | gsub("night"; " morning")
# => "Good morning kittens. Good morning mittens."

Der Ersatztext kann sich auf die übereinstimmenden Teilstrings beziehen; verwende benannte Captures und String-Interpolation.

"Some 3-letter acronyms: gnu, csv, png"
| gsub( "\\b(?<tla>[[:alpha:]]{3})\\b";     # find words 3 letters long
        "\(.tla | ascii_upcase)" )          # upper-case the match
# => "Some 3-letter acronyms: GNU, CSV, PNG"

Flags

In allen oben genannten Filtern ist FLAGS ein String, der aus null oder mehr der unterstützten Flags besteht.

  • g - Globale Suche (alle Treffer finden, nicht nur den ersten)
  • i - Suche ohne Beachtung der Groß-/Kleinschreibung
  • m - Mehrzeilenmodus ('.' passt auch auf Zeilenumbrüche)
  • n - Leere Treffer ignorieren
  • p - Sowohl der s- als auch der m-Modus sind aktiviert
  • s - Einzeilenmodus ('^' -> '\A', '$' -> '\Z')
  • l - Die längstmöglichen Treffer finden
  • x - Erweitertes Regex-Format (Leerraum und Kommentare ignorieren)

Zum Beispiel

"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")

# or with Extended formatting

"JIRAISSUE-1234" | capture("
                     (?<project>   \\w+ )  # the Jira project
                     -                     # followed by a hyphen
                     (?<issue_num> \\d+ )  # followed by digits
                   "; "x")

Anleitung

Du wurdest als Spezialist für reguläre Ausdrücke in einem Unternehmen eingestellt, das einen Chatbot entwickelt.

Er befindet sich in einer sehr frühen Entwicklungsphase. Deine Aufgabe ist es, reguläre Ausdrücke zu verwenden, um die Fähigkeit des Chatbots zu verbessern, natürliche Sprache zu verstehen und zu erzeugen.

1. Gültigen Befehl prüfen

Der Chatbot ist nicht nur schlau, sondern auch ein loyaler Assistent. Um den Chatbot etwas zu fragen, muss der Benutzer das Wort „Chatbot“ an der ersten Position des Befehls sagen. Es spielt keine Rolle, ob das Schlüsselwort in Groß- oder Kleinbuchstaben steht. Wichtig ist die Position des Wortes.

Implementiere die Funktion is_valid_command, die dem Chatbot hilft zu erkennen, wann der Benutzer einen Befehl gibt.

"Chatbot, play a song from the 80's." | is_valid_command
# => true
"Hey Chatbot, where is the closest pharmacy?" | is_valid_command
# => false
"CHATBOT, do you have a solution for this challenge?" | is_valid_command
# => true

2. Verschlüsselte Emojis entfernen

Der Chatbot hat Schwierigkeiten zu verstehen, wie Menschen Emojis verwenden, um ihre Gefühle auszudrücken. Wenn der Chatbot Nachrichten von Benutzern empfängt, wird jedes Emoji als der String „emoji“ dargestellt, gefolgt von einer ID-Nummer.

Implementiere die Methode remove_emoji, die einen String entgegennimmt und alle Emojis aus der Nachricht entfernt.

Zeilen, die keine Emojis enthalten, sollen unverändert zurückgegeben werden. Entferne einfach den String „emoji“. Verändere die Leerzeichen nicht.

"I love playing videogames emoji3465 it's one of my hobbies" | remove_emoji
# => "I love playing videogames  it's one of my hobbies"

3. Gültige Telefonnummer prüfen

Irgendwann während der Interaktion mit dem Chatbot gibt der Benutzer eine Telefonnummer an. Der Chatbot kann nur Nummern in einem bestimmten Format anrufen.

Implementiere die Funktion check_phone_number.

Wenn die Nummer gültig ist, antwortet der Chatbot mit einer Nachricht, in der er sich beim Benutzer bedankt und die Nummer bestätigt. Wenn die Nummer ungültig ist, teilt der Chatbot dem Benutzer mit, dass die Telefonnummer nicht gültig ist.

Das erwartete Format ist (+NN) NNN-NNN-NNN, wobei N eine Ziffer ist.

"chatbot my phone number is (+34) 659-771-594" | check_phone_number
# => "Thanks! Your phone number is OK."
"chatbot, call me at 659-771-594" | check_phone_number
# => "Oops, it seems like I can't reach out to 659-771-594."

Der Chatbot ist eine wirklich neugierige Software. Obwohl er das Internet nach einem bestimmten Thema durchsuchen kann, fragt er Benutzer gern nach coolen Websites, die sie besuchen können, um relevante Informationen zu finden.

Beispielgespräch:

Chatbot: Hey Benutzer, ich würde gern lernen, wie man in JavaScript programmiert. Kennst du eine coole Website, auf der ich das lernen kann?

Benutzer: Ich habe viel auf exercism.org gelernt, dort gibt es jede Menge großartige Sachen.

Implementiere die Funktion get_domains, die ein Array von Website-Domains zurückgibt.

"I learned a lot from exercism.org and google.com" | get_domains
# => ["exercism.org", "google.com"]

5. Den Benutzer begrüßen

Ein höflicher Chatbot spricht Benutzer mit ihrem Namen an. Wenn ein Benutzer sich vorstellt, erkennt unser Chatbot seinen Namen und antwortet mit einer freundlichen Begrüßung.

Schreibe die Funktion nice_to_meet_you.

Wenn der Eingabe-String „My name is Someone.“ enthält, erfasse den Namen und gib den String „Nice to meet you, Someone.“ zurück.

"My name is Jean-Luc" | nice_to_meet_you
# => "Nice to meet you, Jean-Luc"

6. Sehr einfaches CSV-Parsen

Weil wir uns der „schleichenden Funktionswut“ beugen, fügen wir dem Chatbot eine Funktion zum Parsen von CSV hinzu.

Implementiere die Funktion parse_csv, die einen String entgegennimmt und ein Array der resultierenden Felder zurückgibt. Der Feldtrenner soll „Komma plus optionaler Leerraum“ sein.

Wir kümmern uns nicht um die Randfälle des CSV-Formats (etwa Felder, die Kommas enthalten).

"first, second,third,   fourth" | parse_csv
# => ["first", "second", "third", "fourth"]
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
jq Exercism

Bereit, mit Regulärer Chatbot zu starten?

Melde dich bei Exercism an, um jq mit 12 Konzepte75 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.