Tracks
/
jq
jq
/
Lehrplan
/
Reguläre Ausdrücke
Re

Reguläre Ausdrücke in jq

1 Übung

Über Reguläre Ausdrücke

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

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

Regex-Variante

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

Die genaue 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 angegeben. Das bedeutet, dass alle Backslashes im regulären Ausdruck im String escaped werden müssen.

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

Regex-Funktionen

Reguläre Ausdrücke beschränken sich in jq auf eine Reihe von Filtern.

Einfaches Abgleichen

Wenn du wissen willst, ob ein String zu einem Muster passt, verwende 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 die Übereinstimmung

Wenn du den Teilstring extrahieren willst, der tatsächlich zu dem Muster gepasst hat, verwende den match-Filter.

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

Dieser Filter gibt aus:

  • nichts, wenn es keine Übereinstimmung gab, oder
  • ein Objekt mit verschiedenen Eigenschaften, wenn es eine Übereinstimmung gab.

Dieses Beispiel sucht mit der Backref-Syntax \1 nach zwei aufeinanderfolgenden, identischen 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 jede Übereinstimmung 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 eine Übereinstimmung 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)

# note, there is no scan([REGEX, FLAGS]) version, unlike other filters

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 willst, verwende match oder scan. Wenn du die Teile kennst, die du verwerfen willst, verwende split.

STRING | split(REGEX; FLAGS)
Caution

Der einargumentige split-Filter behandelt sein Argument als festen String.

Um einen Regex mit split zu verwenden, musst du das zweite Argument angeben; ein leerer String ist in Ordnung.

Ein Beispiel, das einen String an beliebigen Leerzeichen aufteilt.

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

Das passiert, wenn wir das Argument für die Flags vergessen.

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

Nur ein Ergebnis: der feste String \s+ kam in der Eingabe nicht vor.

Der einargumentige split kann beliebige Leerzeichen nicht verarbeiten. Wenn man an einem Leerzeichen aufteilt, ergibt sich dieses Ergebnis.

"first   second           third fourth" | split(" ")
# => ["first", "", "", "second", "", "", "", "",
#     "", "", "", "", "", "", "third", "fourth" ]

Ersetzungen

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

Um nur die erste Übereinstimmung zu ersetzen, verwende sub. Um alle Übereinstimmungen 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 (findet alle Übereinstimmungen, nicht nur die erste)
  • i - Suche ohne Beachtung der Groß-/Kleinschreibung
  • m - Mehrzeilenmodus ('.' passt auch auf Zeilenumbrüche)
  • n - Leere Übereinstimmungen ignorieren
  • p - Sowohl der s- als auch der m-Modus sind aktiviert
  • s - Einzeilenmodus ('^' -> '\A', '$' -> '\Z')
  • l - Findet die längstmöglichen Übereinstimmungen
  • x - Erweitertes Regex-Format (Leerzeichen 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")
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab

Lerne Reguläre Ausdrücke

Das Üben ist gesperrt

Schalte 1 weitere Übung frei, um Reguläre Ausdrücke zu üben