O espressioni regolari. Potenti ma una brutta bestia da ammaestrare. Tranne che per i nerd linuxiani, loro sanno che ci sono da sempre, dagli albori di Unix.
Per tutti gli altri una brevissima intro. È un po’ come quando per dire OK usate due-punti + trattino + chiusa-parentesi che diventa così 🙂 o così 😦 se la parentesi è aperta.
Ma servono per altre cose, come vedremo.
Lanciamo il nostro interprete Ruby (con l’alias che abbiamo definito all’inizio del corso; in alternativa possiamo usare irb --simple-prompt
):
sì, //
è una regexp, appartenente alla classe Regexp
. Adesso vediamo cosa può fare.
match ci dice se la nostra regexp è contenuta nella stringa; si può indagare meglio, così:
L’operatore =~ restituisce la posizione di dove inizia la regexp (il primo carettere della stringa è lo zeresimo, vero che lo ricordiamo tutti?). Secondo la filosofia di Ruby si può usare in entrambi i modi proposti. Inoltre, al solito, i caratteri maiuscoli sono distinti dai minuscoli.
La tastiera italiana manca del simbolo ~
e per inserirlo c’è bisogno di un piccolo giochino, attenzione a non intrecciarvi i diti:
- Windows: Alt + 126 sul tastierino numerico, se questo manca Alt + Fn + 126
- Linux: AltGr + ì
Suggerimento: passate a Linux, è più facile e versatile.
Ma il bello delle regexp è che trovano le stringhe con i caratteri speciali, esempio
Come si vede il punto vale per qualsiasi carattere, posso continuare a fare confusione tra Sonia e Sofia (tanto loro ormai lo sanno e si sono rassegnate, entrambe).
Ma i caratteri speciali sono millemila, per esempio il maiuscolo/minuscolo lo gestiamo con i:
Se uno si trova a gestire spesso questa roba gli conviene fare un salto in qualche pagina specializzata, per esempio:
Qui solo una tabella riassuntiva
[abc] ogni singolo carattere a, b, c
[^abc] ogni singolo carattere diverso da a, b, c
[a-z] ogni singolo carattere nell'intervallo a-z
[a-zA-Z] ogni singolo carattere nell'intervallo a-z e A-Z
^ inizio della linea
$ fine della linea
\A inizio della stringa
\z fine della stringa
. ogni singolo carattere
\s ogni carattere spazio (anche, p.es. iltab)
\S ogni carattere non spazio
\d ogni cifra numerica [0-9]
\D ogni carattere non cifra numerica
\w ogni parola (lettera, numero, trattino basso)
\W ogni carattere non \w
\b ogni fine di parola
(...) qualunque cosa dentro
(a|b) a o b
a? zero o una a
a* zero o più a
a+ una o più a
a{3} esattamente 3 a
a{3,} 3 o più a
a{3,6} da 3 a 6 a
inoltre ci sono i modificatori
i annulla la distinzione tra maiuscole e minuscole
m il punto corrisponde all'a-capo
x ignora gli spazi
o esegue la sostituzione #(...)
Panico ❓ 😳
Forse è il caso di qualche esempio:
#!/usr/bin/ruby # encoding: UTF-8 # re1.rb testo = """Ecco un piccolo testo con parole comuni, per testare le espressioni regolari. Qualcuna delle parole è ripetuta più d'una volta. Brutta bestia le espressioni regolari!""" parole = testo.scan(/\w+/) puts "Le parole sono:" print parole puts puts "ci sono #{parole.count} parole nel testo" puts "ci sono #{parole.uniq.count} parole uniche nel testo" puts "che sono:" print parole.uniq puts
Notare il solito problema delle lettere accentate.
Un altro esempio, vogliamo estrarre i tag da un tweet, questo:
(no, non so cos’è; usato solo come esempio, è risultato il primo della ricerca).
#!/usr/bin/ruby # encoding: UTF-8 # re1.rb testo = """【RETWEET】ONLY IF YOU WANT NEW FOLLOWERS #TeamFollowBack ✔ #TeamFollowWacky ✔ #500aDay ✔ #1000aDay ✔ #TFB ✔ #FollowFriday ✔ #FF #FollowNGain""" parole = testo.scan(/#\w+/) puts "I tag sono:" print parole puts
OK, per oggi basta, con le regexp si continua prossimamente, ma sappiate che sono una brutta bestia, roba da Perl: in ogni script Perl sembra il luogo di un’esplosione nella fabbrica di segni di punteggiatura (cit.)
😉