Parcours
/
jq
jq
/
Programme
/
Expressions régulières
Ex

Expressions régulières en jq

1 exercice

À propos de Expressions régulières

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.

Variante de 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.

Caution

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".

Fonctions de regex

Dans jq, les expressions régulières se limitent à un ensemble de filtres.

Correspondance simple

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

Informations sur la correspondance

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 :

  • rien s'il n'y a pas de correspondance, ou
  • un objet contenant diverses propriétés s'il y a une correspondance.

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": [] }

Sous-chaînes capturées

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"
#    }

Uniquement les sous-chaînes

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"]

Découpe une string

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)
Caution

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"]
Note

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" ]

Substitutions

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"

Options

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 casse
  • m - Mode multiligne ('.' correspond aux retours à la ligne)
  • n - Ignorer les correspondances vides
  • p - Les modes s et m sont tous les deux activés
  • s - Mode monoligne ('^' -> '\A', '$' -> '\Z')
  • l - Trouver les correspondances les plus longues possibles
  • x - 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")
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet

Apprends Expressions régulières

L'entraînement est verrouillé

Déverrouille 1 exercice de plus pour t'entraîner sur Expressions régulières