Le espressioni regolari (regex) sono sequenze di caratteri che specificano un modello di ricerca all'interno di un testo.
Imparare la sintassi delle espressioni regolari va oltre lo scopo di questo argomento.
Ci concentreremo sulle espressioni che jq mette a disposizione per utilizzare le regex.
Strumenti diversi implementano versioni diverse delle espressioni regolari.
jq incorpora la libreria di regex Oniguruma, in gran parte compatibile con le regex di Perl v5.8.
La sintassi specifica usata da jq si può trovare nel repository GitHub di Oniguruma.
jq non ha alcuna sintassi speciale per le espressioni regolari.
Si esprimono semplicemente come stringhe.
Questo significa che ogni backslash presente nell'espressione regolare deve essere protetto con un carattere di escape nella stringa.
Per esempio, la classe di caratteri delle cifre (\d) va scritta come "\\d".
Le espressioni regolari in jq sono limitate a un insieme di filtri.
Quando ti serve sapere se una stringa corrisponde a un modello, usa il filtro test.
STRING | test(REGEX)
STRING | test(REGEX; FLAGS)
STRING | test([REGEX, FLAGS])
Questo filtro produce un risultato di tipo booleano.
"Hello World!" | test("W") # => true
"Goodbye Mars" | test("W") # => false
Quando ti serve estrarre la sottostringa che corrisponde effettivamente al modello, usa il filtro match.
STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])
Questo filtro produce:
Questo esempio cerca due vocali identiche consecutive usando la sintassi di backreference, \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
# }
# ]
# }
Il filtro match restituisce un oggetto per ogni corrispondenza.
Questo esempio mostra il flag "g" in azione per trovare tutte le vocali.
"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": [] }
Simile al filtro match, il filtro capture restituisce un oggetto se c'è stata una corrispondenza.
STRING | capture(REGEX)
STRING | capture(REGEX; FLAGS)
STRING | capture([REGEX, FLAGS])
L'oggetto restituito è una mappa delle catture con nome.
"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
# "project": "JIRAISSUE",
# "issue_num": "1234"
# }
Il filtro scan è simile a match con il flag "g".
STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)
scan produce uno stream di sottostringhe.
"Goodbye Mars" | scan("[aeiou]")
# => "o"
# "o"
# "e"
# "a"
Usa il costruttore di array [...] per raccogliere le sottostringhe.
"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]
Se conosci le parti della stringa che vuoi mantenere, usa match o scan.
Se conosci le parti che vuoi scartare, usa split.
STRING | split(REGEX; FLAGS)
Il filtro split a un solo argomento tratta il suo argomento come una stringa fissa.
Per usare una regex con split, devi passare il secondo argomento; va bene anche una stringa vuota.
Un esempio che divide una stringa su spazi bianchi arbitrari.
"first second third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
I filtri sub e gsub possono trasformare la stringa di input, sostituendo le porzioni corrispondenti dell'input con una stringa di sostituzione.
Per sostituire solo la prima corrispondenza, usa sub.
Per sostituirle tutte, usa 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."
Il testo di sostituzione può fare riferimento alle sottostringhe corrispondenti; usa le catture con nome e l'interpolazione di stringhe.
"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 tutti i filtri precedenti, FLAGS è una stringa composta da zero o più flag supportati.
g - Ricerca globale (trova tutte le corrispondenze, non solo la prima)i - Ricerca senza distinzione tra maiuscole e minuscolem - Modalità multi riga ('.' corrisponderà anche ai caratteri di nuova riga)n - Ignora le corrispondenze vuotep - Sono abilitate sia la modalità s sia la modalità ms - Modalità riga singola ('^' -> '\A', '$' -> '\Z')l - Trova le corrispondenze più lunghe possibilix - Formato regex esteso (ignora spazi bianchi e commenti)Per esempio
"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")
Sei stato assunto come specialista di espressioni regolari in un'azienda che sta sviluppando un Chatbot.
Il progetto è in una fase di sviluppo molto iniziale. La tua missione è usare le espressioni regolari per migliorare la capacità del Chatbot di comprendere e generare il linguaggio naturale.
Oltre a essere intelligente, il Chatbot è anche un assistente leale. Per chiedere qualcosa al Chatbot, l'utente deve dire la parola «Chatbot» nella prima posizione del comando. Non importa se la parola chiave è in MAIUSCOLO o in minuscolo. La cosa importante è la posizione della parola.
Implementa la funzione is_valid_command che aiuta il Chatbot a riconoscere quando l'utente sta fornendo un comando.
"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
Il Chatbot ha difficoltà a capire come gli esseri umani usano le emoji per esprimere le proprie emozioni. Quando il Chatbot riceve i messaggi degli utenti, ogni emoji è rappresentata dalla stringa "emoji" seguita da un numero id.
Implementa il metodo remove_emoji che prende una stringa e rimuove tutte le emoji presenti nel messaggio.
Le righe che non contengono emoji devono essere restituite senza modifiche. Rimuovi soltanto la stringa dell'emoji. Non modificare gli spazi bianchi.
"I love playing videogames emoji3465 it's one of my hobbies" | remove_emoji
# => "I love playing videogames it's one of my hobbies"
A un certo punto dell'interazione con il Chatbot, l'utente fornirà un numero di telefono. Il Chatbot può chiamare solo un numero con un formato specifico.
Implementa la funzione check_phone_number.
Se il numero è valido, il Chatbot risponde con un messaggio che ringrazia l'utente e conferma il numero. Se il numero non è valido, il Chatbot informa l'utente che il numero di telefono non è valido.
Il formato previsto è (+NN) NNN-NNN-NNN, dove N è una cifra.
"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."
Il Chatbot è un software davvero curioso. Anche se può cercare su internet un argomento specifico, gli piace chiedere agli utenti dei bei siti web da visitare per trovare informazioni pertinenti.
Esempio di conversazione:
Chatbot: Ehi utente, mi piacerebbe imparare a programmare in JavaScript. Conosci qualche bel sito web dove potrei imparare?
Utente: Ho imparato molto da exercism.org, c'è tantissimo materiale interessante lì.
Implementa la funzione get_domains che restituisce un array di domini di siti web.
"I learned a lot from exercism.org and google.com" | get_domains
# => ["exercism.org", "google.com"]
Un Chatbot educato si rivolge agli utenti per nome. Quando un utente si presenta, il nostro Chatbot rileva il suo nome e risponde con un saluto amichevole.
Scrivi la funzione nice_to_meet_you.
Se la stringa di input contiene "My name is Someone.", cattura il nome e restituisci la stringa "Nice to meet you, Someone.".
"My name is Jean-Luc" | nice_to_meet_you
# => "Nice to meet you, Jean-Luc"
Cedendo al «creeping featuritis», aggiungeremo al Chatbot una funzione di analisi dei CSV.
Implementa la funzione parse_csv che prende una stringa e restituisce un array dei campi risultanti.
Il separatore dei campi deve essere la virgola, seguita da spazi bianchi opzionali.
Non ci preoccuperemo di nessuno dei casi limite del formato CSV (come i campi che contengono virgole).
"first, second,third, fourth" | parse_csv
# => ["first", "second", "third", "fourth"]
Iscriviti a Exercism per imparare e padroneggiare jq con 12 concetti75 esercizi e il mentoring di persone reali, tutto gratis.