Les expressions régulières (regex) sont des séquences de caractères qui définissent 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.
Les différents outils implémentent des versions différentes des expressions régulières. jq intègre la bibliothèque regex Oniguruma, largement compatible avec les expressions régulières de Perl v5.8.
La syntaxe précise utilisée par jq se trouve dans le dépôt GitHub d'Oniguruma.
jq ne dispose d'aucune syntaxe spéciale pour les expressions régulières.
Elles s'expriment simplement sous forme de strings.
Cela signifie que toute barre oblique inverse présente dans l'expression régulière doit être échappée dans la string.
Par exemple, la classe de caractères correspondant aux chiffres (\d) doit s'écrire "\\d".
Les expressions régulières dans jq 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 effectivement 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 en utilisant 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 le drapeau "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": [] }
Semblable au 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 association des captures nommées.
"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
# "project": "JIRAISSUE",
# "issue_num": "1234"
# }
Le filtre scan est semblable à match avec le drapeau "g".
STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)
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 chaîne fixe.
Pour utiliser une expression régulière avec split, tu dois fournir le 2ᵉ argument ; tu peux tout à fait utiliser une chaîne vide.
Un exemple qui découpe une string sur des espaces arbitraires.
"first second third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
Les filtres sub et gsub peuvent transformer la chaîne d'entrée, en remplaçant les portions correspondantes de l'entrée par une chaîne de remplacement.
Pour ne remplacer que 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 chaînes.
"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 chaîne composée de zéro ou plusieurs des drapeaux pris en charge.
g - Recherche globale (trouve toutes les correspondances, pas seulement la première)i - Recherche insensible à la cassem - Mode multiligne ('.' correspond aux sauts de ligne)n - Ignore les correspondances videsp - Les modes s et m sont tous les deux activéss - Mode monoligne ('^' -> '\A', '$' -> '\Z')l - Trouve les correspondances les plus longues possiblesx - Format d'expression régulière étendu (ignore les espaces 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")
Tu as été recruté comme spécialiste des expressions régulières dans une entreprise qui développe un Chatbot.
Le projet n'en est qu'à une phase de développement très basique. Ta mission est d'utiliser les expressions régulières pour améliorer la capacité du Chatbot à comprendre et à générer du langage naturel.
En plus d'être intelligent, le Chatbot est aussi un assistant fidèle. Pour demander quelque chose au Chatbot, l'utilisateur doit dire le mot « Chatbot » en première position de la commande. Peu importe que le mot-clé soit en majuscules ou en minuscules. Ce qui compte, c'est la position du mot.
Implémente la fonction is_valid_command qui aide le Chatbot à reconnaître quand l'utilisateur donne une commande.
"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
Le Chatbot a du mal à comprendre comment les humains utilisent les emojis pour exprimer leurs émotions. Quand le Chatbot reçoit des messages d'utilisateurs, chaque emoji est représenté par la string « emoji » suivie d'un numéro d'identification.
Implémente la méthode remove_emoji qui prend une string et supprime tous les emojis du message.
Les lignes qui ne contiennent pas d'emoji doivent être renvoyées telles quelles. Supprime simplement la string « emoji ». Ne touche pas aux espaces.
"I love playing videogames emoji3465 it's one of my hobbies" | remove_emoji
# => "I love playing videogames it's one of my hobbies"
À un moment ou un autre de l'interaction avec le Chatbot, l'utilisateur va fournir un numéro de téléphone. Le Chatbot ne peut appeler qu'un numéro ayant un format bien précis.
Implémente la fonction check_phone_number.
Si le numéro est valide, le Chatbot répond par un message qui remercie l'utilisateur et confirme le numéro. Si le numéro n'est pas valide, le Chatbot informe l'utilisateur que le numéro de téléphone est invalide.
Le format attendu est (+NN) NNN-NNN-NNN, où N est un chiffre.
"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."
Le Chatbot est un logiciel vraiment curieux. Même s'il peut chercher sur internet un sujet particulier, il aime demander aux utilisateurs quels sites intéressants visiter pour trouver des informations pertinentes.
Exemple de conversation :
Chatbot : Bonjour Utilisateur, j'aimerais apprendre à coder en JavaScript. Tu connais un site sympa où je pourrais apprendre ?
Utilisateur : J'ai beaucoup appris sur exercism.org, il y a plein de choses géniales là-bas.
Implémente la fonction get_domains qui renvoie un tableau de domaines de sites web.
"I learned a lot from exercism.org and google.com" | get_domains
# => ["exercism.org", "google.com"]
Un Chatbot poli s'adresse aux utilisateurs par leur nom. Quand un utilisateur se présente, notre Chatbot détecte son nom et répond par un salut amical.
Écris la fonction nice_to_meet_you.
Si la string d'entrée contient « My name is Someone. », capture le nom et renvoie la string « Nice to meet you, Someone. ».
"My name is Jean-Luc" | nice_to_meet_you
# => "Nice to meet you, Jean-Luc"
Cédant à la tentation d'en faire toujours plus, nous allons ajouter une fonction d'analyse CSV au Chatbot.
Implémente la fonction parse_csv qui prend une string et renvoie un tableau des champs obtenus.
Le séparateur de champs doit être « une virgule suivie d'espaces facultatifs ».
On ne se préoccupera pas des cas limites du format CSV (comme les champs contenant des virgules).
"first, second,third, fourth" | parse_csv
# => ["first", "second", "third", "fourth"]
Inscris-toi sur Exercism pour apprendre et maîtriser jq avec 12 concepts75 exercices, et un vrai mentorat humain, le tout gratuitement.