Les expressions régulières (les regex) sont des séquences de caractères qui décrivent un motif de recherche dans un texte.
Apprendre la syntaxe des expressions régulières dépasse le cadre de ce sujet.
On va se concentrer sur les expressions que jq fournit pour utiliser les regex.
Différents outils implémentent différentes versions des expressions régulières.
jq intègre la bibliothèque d'expressions régulières Oniguruma, largement compatible avec les regex de Perl v5.8.
La syntaxe spécifique utilisée par jq se trouve sur le dépôt GitHub d'Oniguruma.
jq n'a pas de syntaxe particulière pour les expressions régulières.
Elles s'expriment simplement sous forme de string.
Cela signifie que toutes les barres obliques inverses présentes dans l'expression régulière doivent être échappées dans la string.
Par exemple, la classe de caractères des chiffres (\d) doit s'écrire "\\d".
Dans jq, les expressions régulières se limitent à un ensemble de filtres.
Quand tu as besoin de savoir si une string correspond à un motif, utilise le filtre test.
STRING | test(REGEX)
STRING | test(REGEX; FLAGS)
STRING | test([REGEX, FLAGS])
Ce filtre produit un résultat booléen.
"Hello World!" | test("W") # => true
"Goodbye Mars" | test("W") # => false
Quand tu as besoin d'extraire la sous-chaîne qui correspond réellement au motif, utilise le filtre match.
STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])
Ce filtre produit :
Cet exemple recherche deux voyelles identiques consécutives à l'aide de la syntaxe de référence arrière, \1.
"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
# }
# ]
# }
Le filtre match renvoie un objet pour chaque correspondance.
Cet exemple montre l'option "g" en action pour trouver toutes les voyelles.
"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": [] }
Comme le filtre match, le filtre capture renvoie un objet s'il y a une correspondance.
STRING | capture(REGEX)
STRING | capture(REGEX; FLAGS)
STRING | capture([REGEX, FLAGS])
L'objet renvoyé est une mise en correspondance des captures nommées.
"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
# "project": "JIRAISSUE",
# "issue_num": "1234"
# }
Le filtre scan est similaire à match avec l'option "g".
STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)
# note, there is no scan([REGEX, FLAGS]) version, unlike other filters
scan produit un flux de sous-chaînes.
"Goodbye Mars" | scan("[aeiou]")
# => "o"
# "o"
# "e"
# "a"
Utilise le constructeur de tableau [...] pour capturer les sous-chaînes.
"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]
Si tu connais les parties de la string que tu veux garder, utilise match ou scan.
Si tu connais les parties que tu veux écarter, utilise split.
STRING | split(REGEX; FLAGS)
Le filtre split d'arité 1 traite son argument comme une string fixe.
Pour utiliser une regex avec split, tu dois fournir le deuxième argument ; tu peux très bien utiliser une string vide.
Un exemple qui découpe une string sur des espaces blancs arbitraires.
"first second third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
Voici ce qui se passe si on oublie l'argument des options.
"first second third fourth" | split("\\s+")
# => ["first second third fourth"]
Un seul résultat : la string fixe \s+ n'apparaît pas dans l'entrée.
Le split d'arité 1 ne peut pas gérer des espaces blancs arbitraires.
Découper sur un espace donne ce résultat.
"first second third fourth" | split(" ")
# => ["first", "", "", "second", "", "", "", "",
# "", "", "", "", "", "", "third", "fourth" ]
Les filtres sub et gsub peuvent transformer la string d'entrée, en remplaçant les portions correspondantes de l'entrée par une string de remplacement.
Pour remplacer uniquement la première correspondance, utilise sub.
Pour remplacer toutes les correspondances, utilise 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."
Le texte de remplacement peut faire référence aux sous-chaînes correspondantes ; utilise des captures nommées et l'interpolation de string.
"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"
Dans tous les filtres ci-dessus, FLAGS est une string composée de zéro ou plusieurs des options prises en charge.
g - Recherche globale (trouver toutes les correspondances, pas seulement la première)i - Recherche insensible à la cassem - Mode multiligne ('.' correspond aux retours à la ligne)n - Ignorer les correspondances videsp - Les modes s et m sont tous les deux activéss - Mode monoligne ('^' -> '\A', '$' -> '\Z')l - Trouver les correspondances les plus longues possiblesx - Format de regex étendu (ignorer les espaces blancs et les commentaires)Par exemple
"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")