POSIX Regular expressions on tak3z0u's articles

Versione italiana

Any english reader, people knowing english and that are not scared by it, can read the manual that can easily be found on a GNU/Linux system, try man 7 regex or something like that, or find in the Interner POSIX 1003.2 regex. This is the suggested thing to do for everyone.

Regular expressions are the kind of expression used to select text according to rules/patterns. MS-DOS/MS-Windows users know better what it is sometimes called globbing, for example they know that *.jpg matches any string that ends with .jpg. POSIX reg. ex. can do this and more.

Just remember that if you provide a wrong regex, errors will be ignored, so it's sure you won't see any result for that search pattern! And the regex in the Search Article section of this site could be limited for several reasons.

IMPORTANT: you need backslash escaping for the backslash itself; e.g. \\?$|windows works, \?$|windows does not.

Le espressioni regolari POSIX per gli articoli su tak3z0u

Le espressioni regolari sono quel genere di espressione che usereste per selezionare un testo (o una porzione di esso) secondo certe regole e/o pattern. Per esempio, se inizia con una lettera maiuscola e finisce in .jpg, oppure se contiene numeri e così via.

Gli utenti MS-DOS per esempio sanno che * vuol dire una qualunque sequenza di 0 o più caratteri, mentre ? vuol dire un qualunque carattere. Le espr. regolari (da ora in poi regex) possono questo e altro.

Ognuno si può inventare le proprie regex naturalmente, ma anche qui può essere conveniente convergere su alcune convenzioni. Quelle che andiamo ad esplorare brevemente sono le regex secondo lo standard POSIX 1003.2, per l'uso che ne possiamo fare all'interno di questo sito, nella sezione Ricerca Articoli.

Per capire bene il punto supponiamo di avere un testo con dentro un elenco di titoli. Vogliamo selezionare tutti i titoli che contengono un numero. Come faremmo usando una regex? Attraversa essa semplicemente esprimeremmo il fatto che dove compare un qualunque numero composto da una o più cifre, quel titolo ci interessa.

Questo nelle regex POSIX si dice semplicemente come [[:digit:]]+, ma potremmo anche scrivere [0-9]+. Questo si legge così: [0-9] crea una lista di caratteri, precisamente le cifre dal 0 al nove; il + è un quantificatore, che dice di accettare una sequenza composta da uno o più caratteri di quel tipo/classe. Per l'appunto la sintassi [: :] indica una classe, nel primo esempio la classe cifre (digit). Utili le classi per non scrivere un elenco di caratteri, per esempio per gli alfanumerici minuscoli e maiucoli dovremmo scrivere [a-zA-Z0-9], invece possiamo scrivere [[:alnum:]] equivalentemente, a vantaggio anche della chiarezza. NOTA: nel sito la ricerca è insensibile al minuscolo/maiuscolo, per cui USA è del tutto equivalente a usa, per dire.

Con questo, selezioniamo tutti i titoli dove compaiono dei numeri.

Se ci interessano semplicemente i titoli in cui compare la parola o frammento usa, basta digitare appunto usa. Ma questo selezionerebbe anche titoli del tipo Delusation Row. Se vogliamo invece proprio solo la parola, allora dobbiamo sottolineare che essa o deve essere la prima, seguita da uno o più spazi, o in mezzo ma preceduta da uno o più spazi, o infine, l'ultima. Invece di spazi, possiamo considerare anche segni di punteggiatura.

L'espressione regolare per selezionare solo USA come parola è ^usa[ \t,.;:?!]+|[ \t,.;:?!]+usa[ \t,.;:?!]+|usa[.!?]*$, che è piuttosto complessa... Vediamo cosa dice. Innanzi tutto, il | separa diverse possibilità. Quindi abbiamo tre frammenti da considerare.

Il primo dice di accettare pattern che iniziano (^) con la parola usa seguita da uno o più (+) spazi, oppure tab (tabulazione), virgole, punti, punti e virgola, due punti, punti interrogativi o punti esclamativi. Questo fa accettare titoli del tipo: Usa il gatto, oppure Usa!, ma anche lo sgrammaticato Usa...!, !?;:, per dire.

Il secondo frammento, non avendo vincoli inizio (^) né fine ($) come il successivo, fa selezionare tutti i titoli nei quali la parola USA compare preceduta e seguita da uno o più dei caratteri nel solito elenco. Quindi Bye bye,...USA...cari! o simili.

Infine l'ultimo, che sembra ridondante ma non lo è tanto, seleziona tutti i titoli che terminano con usa seguito da niente o da una sequenza arbitraria di punti, punti esclamativi o interrogativi. La differenza rispetto a quello centrale è che questo cattura anche titoli come Vengono dagli USA, senza niente in fondo. Però, questo prende anche titoli come Comprato da Aretusa!, poiché non si dice cosa deve precedere USA. Se vogliamo mantenere USA come parola, allora l'ultima regex deve essere qualcosa come [ \t,.;:?!]+usa[.!?]*.

Nell'elenco dei caratteri [ \t,.;:?!] si possono aggiungere tutti quei caratteri che si suppone separano delle parole, per esempio qui non ho messo il -, che andrebbe messo per catturare titoli tipo Proteste anti-USA.

Come si nota, selezionare un titolo in cui compare una sequenza di lettere da intendersi solo come parola non è banale. Si può trovare però un diverso modo per dire la stessa cosa: in fondo, per evitare che USA sia un frammento di una parola, basta assicurarsi che non sia seguito o preceduto da uno o più lettere! Allora la regex più semplice [^a-z]+usa[^a-z]+ fa al caso nostro.

Esploriamo ora i quantificatori. Essi seguono il gruppo o singolo carattere o frammento di regex (in generale, un atomo) da quantificare.

Per esempio a+ seleziona un titolo che contiene da qualche parte una a, o una sequenza arbitraria di a, tipo aa, aaa, aaaa etc. Oppure, (ar)+ che seleziona titolo dove compare ar, arar, ararar e così via. Oppure [che]+ che seleziona titoli dove compaiono cose del tipo c, cc, ccc etc, oppure che, ehc, hce etc, oppure chh, chhh, cch, ecchh etc. etc., insomma una sequenza di zero o più caratteri scelti arbitrariamente volta per volta dall'elenco dato.

Invece, a* selezionerebbe un titolo dove compaiono zero o più a di seguito, cioè titoli dove compare o nessuna a, oppure una a, oppure un aa etc. etc. In pratica, mostra tutti i titoli! L'uso più classico è .*, dove il punto sta per qualunque carattere, e dunque è l'equivalente MS-DOSsiano di *, o Amighista di #?.

Se cerchiamo un titolo in cui compaia HTML, ma non sappiamo se ce la mettiamo o no la L finale (purtroppo spesso le estensioni si intendono di tre lettere a causa del vecchio MS-DOS e dei suoi eredi), possiamo usare la regex html?; si noti appunto che il ? si riferisce all'atomo precedente, che qui è solo l. Se volessimo controllare per HT o HTML, dovremmo scrivere ht(ml)?.

Infine, supponiamo di voler selezionare i titoli dove compaiono due o più o, usiamo o{2,}, oppure dove ne compaiono esattamente due, o{2} etc.

Importante notare che quando scriviamo per esempio o{2} e diciamo che seleziona titolo dove compaiono due o di seguito, tipo oo, intendiamo che tale sequenza può comparire anche più di una volta, come per esempio in Google vs Google.

Quasi tutte queste regex viste non hanno un ancoraggio specifico, cioè possono comparire ovunque. Se vogliamo invece che debbano comparire in testa o in fondo al nostro titolo, usiamo ^ all'inizio, e $ per la fine. Tecnicamente diciamo che tali caratteri selezionano la stringa nulla all'inizio e alla fine rispettivamente del titolo.

Dunque se vogliamo selezionare tutti i titolo che iniziano per a, scriviamo ^a. Se vogliamo selezionare tutti i titoli che non iniziano per a, scriviamo ^[^a], si noti il diverso significato di ^ come primo carattere dopo [.

Se vogliamo selezionare tutti i titoli che terminano per punto esclamativo, scriviamo !$.

Si noti che scrivere ^a è equivalente a scrivere ^a.* così come usa è equivalente a .*usa.*, ricordando che il punto indica un carattere qualunque.

E se vogliamo selezionare tutti i titoli che terminano con punto, invece che con punto esclamativo? Scrivendo .$ commettiamo un errore, perché questa regex seleziona un titolo terminante per qualunque carattere, cioè, tutti i titoli! I caratteri speciali, che hanno un significato speciale, per farli intendere non come caratteri speciali, vanno fatti precedere da \, che a sua volta diventa un carattere speciale per cui se cerchiamo titolo con una barra inversa, dobbiamo scrivere \\. Dunque, titoli terminanti con punto si cercano così: \.$.

Dunque, vogliamo trovare articoli il cui titolo contenga una parentesi tonda aperta? Cerchiamo \(; ma se vogliamo un titolo che contenga una parentesi aperta o chiusa, possiamo scrivere [()] senza problemi, oppure [\(\)], funziona ugualmente.

Se cerchiamo titoli con il più, cerchiamo \+ e così via.

Le classi che abbiamo a disposizione di base sono:

alnum
tutti i caratteri alfanumerici (lettere maiuscole/minuscole e numeri)
alpha
tutto l'alfabeto, minuscolo e maiuscolo
digit
le cifre
blank
spazio o tabulazione
cntrl
caratteri di controllo
graph
caratteri stampabili eccetto lo spazio
lower
alfabetici minuscole
print
tutti i caratteri stampabili
punct
punteggiatura (ovvero non alfanumerici e blank)
space
spazi (spazio, tabulazione orizzontale e verticale, fine pagine, accapo, ritorno carrello)
upper
lettere maiuscole
xdigit
cifre esadecimali (oltre i numeri, anche le lettere A B C D E F)

Per concludere, uno o più frammenti alternativi possono essere separati da | come visto in un esempio sopra.

Per quanto riguarda le regex POSIX, in pratica abbiamo terminato. Bisogna ricordare che inserendo l'espressione nel campo opportuno può essere necessario aggiungere un backslash per il backslash medesimo, cioè per esempio \\?$|guerra invece di \?$|guerra. Proseguiamo per chi vuole vedere ancora qualche esempio.


Home page