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.
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.
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.
Reguläre Ausdrücke beschränken sich in jq auf eine Reihe von Filtern.
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
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:
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": [] }
Ä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"
# }
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"]
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)
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"]
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" ]
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"
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ß-/Kleinschreibungm - Mehrzeilenmodus ('.' passt auch auf Zeilenumbrüche)n - Leere Übereinstimmungen ignorierenp - Sowohl der s- als auch der m-Modus sind aktivierts - Einzeilenmodus ('^' -> '\A', '$' -> '\Z')l - Findet die längstmöglichen Übereinstimmungenx - 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")