Track
/
jq
jq
/
Esercizi
/
Chatbot a espressioni regolari
Chatbot a espressioni regolari

Chatbot a espressioni regolari

Esercizio di apprendimento

Introduzione

Espressioni regolari

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.

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

Caution

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

Funzioni per le regex

Le espressioni regolari in jq sono limitate a un insieme di filtri.

Corrispondenza semplice

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
Informazioni sulla corrispondenza

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:

  • niente, se non c'è stata alcuna corrispondenza, oppure
  • un oggetto che contiene varie proprietà, se c'è stata una corrispondenza.

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

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"
#    }
Solo le sottostringhe

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"]
Dividere una stringa

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

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

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"

Flag

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 minuscole
  • m - Modalità multi riga ('.' corrisponderà anche ai caratteri di nuova riga)
  • n - Ignora le corrispondenze vuote
  • p - Sono abilitate sia la modalità s sia la modalità m
  • s - Modalità riga singola ('^' -> '\A', '$' -> '\Z')
  • l - Trova le corrispondenze più lunghe possibili
  • x - 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")

Istruzioni

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.

1. Verifica un comando valido

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

2. Rimuovi le emoji criptate

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"

3. Verifica un numero di telefono valido

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

5. Saluta l'utente

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"

6. Analisi CSV molto semplice

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"]
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
jq Exercism

Vuoi iniziare Chatbot a espressioni regolari?

Iscriviti a Exercism per imparare e padroneggiare jq con 12 concetti75 esercizi e il mentoring di persone reali, tutto gratis.