Windows PowerShellScrittura di espressioni regolari

Don Jones

192.168.4.5. \\Server57\Share. johnd@contoso.com. Sono certo che i lettori riconosceranno immediatamente queste tre stringhe, identificandone i formati come corrispondenti, nell'ordine, a un indirizzo IP, a un percorso UNC (Universal Naming Convention) e a un indirizzo di posta elettronica. I quattro gruppi di cifre, le barre rovesciate, il simbolo @ e altri elementi indicano chiaramente il tipo di dati rappresentato da queste

stringhe di caratteri. Sarà sufficiente appena qualche attimo di riflessione per mettere a fuoco che in realtà 192.168.4.5 non è un indirizzo IP valido, così come \\Server57\Share non è un percorso UNC valido e johnd@contoso.com non è un indirizzo di posta elettronica valido.

I computer, purtroppo, devono sforzarsi un po' di più per "riconoscere" formati complicati come questi. Ed ecco dove entrano in gioco le espressioni regolari. Un'espressione regolare è una stringa scritta con l'ausilio di uno speciale linguaggio, che aiuta un computer a identificare altre stringhe di un particolare formato, ad esempio indirizzi IP, UNC o indirizzi di posta elettronica. Se scritta in modo appropriato, un'espressione regolare consente a uno script di Windows PowerShellTM di accettare in quanto validi o rifiutare in quanto non validi i dati immessi a seconda che siano conformi o meno al formato specificato.

Corrispondenze semplici

L'operatore –match di Windows PowerShell confronta una stringa con un'espressione regolare e restituisce True o False a seconda che la stringa corrisponda o meno all'espressione in questione. Nel caso di espressioni regolari molto semplici, non è necessaria nemmeno una sintassi speciale. È sufficiente infatti che vengano utilizzati caratteri letterali. Ad esempio:

"Microsoft" –match "soft"
"Software" –match "soft"
"Computers" –match "soft"

Se eseguite in Windows PowerShell, le prime due espressioni restituiscono True mentre la terza restituisce False. In ciascuna di esse, una stringa è seguita da un operatore –match, che a sua volta è seguito da un'espressione regolare. Per impostazione predefinita, un espressione regolare scorre la stringa di input per trovare una corrispondenza. La sequenza di caratteri "soft" è presente sia in Software che in Microsoft, sebbene in posizioni differenti. Si tenga presente inoltre che, per impostazione predefinita, un'espressione regolare non è sensibile alla distinzione tra maiuscole e minuscole: la sequenza di caratteri "soft" viene trovata infatti in "Software" nonostante la lettera maiuscola S.

Tuttavia, se necessario, un operatore differente, –cmatch, consente di confrontare espressioni regolari tenendo conto della distinzione tra maiuscole e minuscole, come nell'esempio seguente:

"Software" –cmatch "soft"

Questa espressione restituisce False poiché non viene individuata alcuna corrispondenza tra "soft" e "Software" in un confronto che rileva la distinzione tra maiuscole e minuscole. Si noti che l'operatore –imatch è disponibile anche come opzione esplicita per un confronto senza distinzione tra maiuscole e minuscole, sebbene questo sia il comportamento predefinito di –match.

Caratteri jolly e ripetitori

Un'espressione regolare può contenere un numero limitato di caratteri jolly. Un punto, ad esempio, corrisponde a un'istanza di qualsiasi carattere, mentre un punto interrogativo corrisponde a zero o a un'istanza di qualsiasi carattere. Ecco di seguito qualche esempio:

"Don" –match "D.n" (True)
"Dn" –match "D.n" (False)
"Don" –match "D?n" (True)
"Dn" –match "D?n" (True)

Nella prima espressione, il punto sostituisce esattamente un carattere, quindi la corrispondenza è True. Nella seconda espressione, invece, il punto non trova il singolo carattere necessario da includere, pertanto la corrispondenza è False. Il punto interrogativo, come mostrato nella terza e nella quarta espressione, può corrispondere a un unico carattere sconosciuto o a nessun carattere. Quindi nel quarto esempio la corrispondenza è True in quanto vengono trovati sia "D" che "n" senza un carattere che li separi. In sostanza, dunque, si può dire che il punto interrogativo rappresenti un carattere facoltativo, per cui la corrispondenza risulta True anche se in quella data posizione non vi è alcun carattere.

Un'espressione regolare è in grado di riconoscere anche i simboli * e + come ripetitori. Questi simboli devono seguire uno o più caratteri. In particolare, il simbolo * corrisponde a zero o più caratteri specificati, mentre il simbolo + corrisponde a uno o più caratteri specificati. Ecco alcuni esempi:

"DoDon" –match "Do*n" (True)
"Dn" -match "Do*n" (True)
"DoDon" -match "Do+n" (True)
"Dn" -match "Do+n" (False)

Si noti che sia il simbolo * che il simbolo + corrispondono alla stringa "Do", non semplicemente al carattere "o". Questi ripetitori infatti sono stati progettati per corrispondere a una serie di caratteri e non a uno solo.

Ecco come bisogna procedere se si desidera cercare le corrispondenze del punto e dei simboli *, ? o +. È sufficiente farli precedere da una barra rovesciata, che è il carattere escape delle espressioni regolari:

"D.n" -match "D\.n" (True)

Come si può notare, questo carattere differisce dal carattere escape di Windows PowerShell, ovvero l'apostrofo inverso, ma segue la sintassi delle espressioni regolari standard del settore.

Classi di caratteri

Una classe di caratteri è una forma più estesa di carattere jolly e rappresenta un intero gruppo di caratteri. Windows PowerShell riconosce solo un numero limitato di classi di questo tipo, ad esempio:

  • \w corrisponde a un qualsiasi carattere alfanumerico, ovvero lettere e numeri.
  • \s corrisponde a un qualsiasi carattere che rappresenti uno spazio bianco, ad esempio una tabulazione, uno spazio e così via.
  • \d corrisponde a una qualsiasi carattere numerico.

Esistono anche classi di caratteri negativi: \W corrisponde a un qualsiasi carattere non alfanumerico, \S a un qualsiasi carattere che non sia uno spazio bianco e \D a un qualsiasi carattere che non sia una numero. Queste classi possono essere seguite dai simboli * o + per indicare che sono ammesse più corrispondenze. Ecco alcuni esempi:

"Shell" -match "\w" (True)
"Shell" -match "\w*" (True)

Cmdlet del mese

Il cmdlet Write-Debug è molto utile per la scrittura di oggetti, come stringhe di testo, nella pipeline Debug. Tuttavia, l'utilizzo di questo cmdlet nella shell può risultare piuttosto deludente, in quanto sembra che non produca alcun effetto.

Il trucco è che la pipeline Debug è disattivata per impostazione predefinita: la variabile $DebugPreference è infatti impostata su "SilentlyContinue". Sarà sufficiente impostarla su "Continue" e tutti i dati trasmessi con Write-Debug verranno visualizzati nella console sotto forma di testo di colore giallo. Si tratta di un metodo ideale per aggiungere codice traccia ai propri script, con la possibilità di seguire l'esecuzione di uno script complesso. Il colore giallo aiuta a distinguere il codice traccia dal normale output dello script ed è possibile disattivare i messaggi di debug in qualsiasi momento senza dover rimuovere tutte le istruzioni Write-Debug. Basta impostare nuovamente $DebugPreference su "SilentlyContinue" e il testo relativo al debug verrà eliminato.

Sebbene entrambe le espressioni restituiscano True, in realtà le corrispondenze nei due casi differiscono considerevolmente. Fortunatamente, esiste un modo per capire il procedimento logico applicato dall'operatore –match: ogni volta che viene trovata una corrispondenza, una variabile speciale denominata $matches viene popolata con i relativi risultati, ovvero tutti i caratteri della stringa per cui l'operatore ha individuato una corrispondenza in base all'espressione regolare. La variabile $matches conserva i risultati finché non viene eseguito un nuovo confronto con esito positivo mediante l'operatore –match. Nella Figura 1 viene illustrata la differenza tra le due espressioni che ho appena descritto. Come si può osservare, \w trova la corrispondenza di "S" in "Shell", mentre \w* trova la corrispondenza dell'intera parola.

Figura 1 La semplice aggiunta di un simbolo * può essere determinante.

Figura 1** La semplice aggiunta di un simbolo * può essere determinante. **(Fare clic sull'immagine per ingrandirla)

Gruppi, intervalli e dimensioni di caratteri

Un'espressione regolare può contenere anche gruppi o intervalli di caratteri, racchiusi tra parentesi quadre. Ad esempio, [aeiou] indica che qualsiasi carattere tra quelli specificati tra parentesi, ovvero a, e, i, o, u, è una corrispondenza accettabile. [a-zA-Z] indica invece che qualsiasi lettera compresa nell'intervallo a-z o A-Z è accettabile, sebbene, se si utilizza l'operatore –match che non è sensibile alla distinzione tra maiuscole e minuscole, è sufficiente specificare semplicemente a-z o A-Z. Ecco un esempio:

"Jeff" -match "J[aeiou]ff" (True)
"Jeeeeeeeeeeff" -match "J[aeiou]ff" (False)

Con l'ausilio delle parentesi graffe, è anche possibile specificare un numero minimo e un numero massimo di caratteri. {3} indica, ad esempio, che si desidera trovare tre occorrenze, {3,} indica invece che si desidera trovare almeno tre occorrenze e {3,4}, infine, che si desidera trovare almeno tre ma non più di quattro occorrenze del carattere specificato. Quella appena illustrata rappresenta un'ottima soluzione per creare espressioni regolari per gli indirizzi IP:

"192.168.15.20" -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" (True)

L'espressione regolare sopra riportata richiede quattro gruppi contenenti ciascuno da uno a tre numeri, separati da un punto letterale. Ma si consideri ora l'esempio seguente:

"300.168.15.20" -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" (True)

Appaiono qui evidenti i limiti di un'espressione regolare. Sebbene infatti il formato di questa stringa sia simile a quello di un indirizzo IP, è chiaro tuttavia che non si tratta di un indirizzo IP valido. Un'espressione regolare non è in grado di determinare la validità dei dati ma solo la correttezza del formato.

Come rendere le espressioni di tipo non-float

La risoluzione dei problemi correlati alle espressioni regolari può essere difficoltosa. Ad esempio, di seguito è riportata un'espressione la cui finalità è quella di testare un percorso UNC nel formato \\Server2\Share:

"\\Server2\Share" -match "\\\\\w+\\\w+" (True)

In questo caso, l'espressione regolare è di per sé difficile da leggere in quanto ogni barra rovesciata letterale da testare deve essere preceduta dal carattere escape, ovvero da una seconda barra rovesciata. Sebbene tutto sembri funzionare correttamente, in realtà non è così:

"57\\Server2\Share" -match "\\\\\w+\\\w+" (True)

Il percorso di questo secondo esempio è, almeno per me, ma non per l'espressione regolare, palesemente un percorso UNC non valido. Perché? Si ricordi che, per impostazione predefinita, un'espressione regolare è di tipo float. Questa espressione regolare si limita a ricercare due barre rovesciate, uno o più caratteri alfanumerici, una nuova barra rovesciata e altri caratteri alfanumerici. Tale schema è effettivamente presente nella stringa di input, ma sono anche presenti alcune cifre supplementari, che rendono il percorso UNC non valido. La soluzione in questo caso consiste nel fare in modo che l'espressione regolare inizi a ricercare le corrispondenze a partire dall'inizio della stringa. A tale scopo, è possibile procedere nel modo seguente:

"57\\Server2\Share" -match "^\\\\\w+\\\w+" (False)

Il carattere ^ indica l'inizio della stringa. Aggiungendo questo carattere, il percorso UNC non valido ha esito negativo in quanto l'espressione regolare ricerca come primi due caratteri della stringa due barre rovesciate e, in questo caso, non le trova.

Analogamente, il simbolo $ può essere utilizzato per indicare la fine di una stringa. Nel caso specifico di un percorso UNC, tuttavia, non risulterebbe di grande utilità poiché questo tipo di percorso può contenere segmenti aggiuntivi, ad esempio \\Server2\Share\Folder\File. Sono certo però che esistono molte situazioni in cui può essere necessario specificare la fine di una stringa.

Supporto per l'utilizzo delle espressioni regolari

In Windows PowerShell, l'argomento della Guida dedicato alle espressioni regolari offre assistenza sulla sintassi di base per il linguaggio di questo tipo di espressioni, ma le risorse in linea forniscono una quantità maggiore di informazioni. Ad esempio, in uno dei miei siti Web preferiti, www.RegExLib.com, è disponibile una libreria gratuita di espressioni regolari scritte per svariati scopi con il contributo degli utenti. È possibile eseguire ricerche sulla base di parole chiave, ad esempio "e-mail" o "UNC", per individuare rapidamente un'espressione regolare che può soddisfare le proprie esigenze o rappresentare un buon punto di partenza. Se si riesce a creare una buona espressione regolare, è possibile aggiungerla alla libreria in modo da renderla disponibile anche per altri utenti.

Un altro sito che trovo molto utile è RegexBuddy (www.RegexBuddy.com). Questo sito fornisce un economico editor grafico per le espressioni regolari. RegexBuddy semplifica l'assemblaggio di un'espressione regolare complessa e consente di testare facilmente qualsiasi espressione di questo tipo per verificare che accetti solo le stringhe valide, rifiutando invece quelle non valide. Anche altri sviluppatori software hanno creato editor e tester di espressioni regolari, disponibili in versione gratuita, shareware o commerciale, che gli utenti troveranno senz'altro interessanti.

Utilizzo delle espressioni regolari

Forse i lettori si staranno chiedendo il motivo per il quale dovrebbero utilizzare le espressioni regolari nella vita reale. Immaginiamo di dover leggere informazioni da un file CSV e di doverle utilizzarle per creare nuovi utenti in Active Directory®. Se il file CSV è stato generato da qualcun altro, con ogni probabilità si vorrà verificare che i dati all'interno siano corretti. Un'espressione regolare è la soluzione ideale per questo tipo di attività. Un'espressione regolare semplice come \w+, ad esempio, è in grado di controllare che i nomi e i cognomi non contengano simboli o caratteri speciali, mentre un 'espressione più complessa consente di controllare che gli indirizzi di posta elettronica siano conformi allo standard aziendale. Ad esempio, si potrebbe utilizzare l'espressione seguente:

"^[a-z]+\.[a-z]+@contoso.com$"

Questa espressione regolare richiede un indirizzo di posta elettronica nel formato don.jones@contoso.com, in cui il nome e il cognome possono contenere solo lettere e devono essere separati da un punto. Gli indirizzi di posta elettronica, tra l'altro, sono tra le cose più complicate per cui scrivere un'espressione regolare. Se si è in grado di restringere l'ambito a uno specifico standard aziendale, sarà molto più facile raggiungere l'obiettivo.

Non vanno dimenticati i simboli di inizio e fine (^ e $), che garantiscono che nulla segua contoso.com e che nulla preceda i caratteri che compongono il nome dell'utente.

In effetti l'utilizzo di questa espressione regolare in Windows PowerShell è piuttosto semplice. Se si presume che la variabile $email contenga l'indirizzo di posta elettronica letto dal file CSV, un'espressione simile alla seguente consentirà di verificare se l'indirizzo è valido:

$regex = "^[a-z]+\.[a-z]+@contoso.com$"
If ($email –notmatch $regex) {
  Write-Error "Invalid e-mail address $email" 
}

In questo esempio viene introdotto anche un nuovo operatore: -notmatch restituisce True se la stringa non corrisponde all'espressione regolare fornita (esiste anche un operatore –cnotmatch per i confronti con distinzione tra maiuscole e minuscole).

Sono ancora molti gli argomenti da trattare in merito alle espressioni regolari che non mi è stato possibile affrontare in questa sede, ad esempio le classi di caratteri aggiuntive, le operazioni più avanzate, altri operatori e naturalmente il tipo di oggetto [regex] supportato da Windows PowerShell. Tuttavia, quanto ho illustrato in questa rapida panoramica sulla sintassi delle espressioni regolari dovrebbe essere sufficiente per iniziare. Chiunque abbia bisogno di aiuto per districarsi con un'espressione regolare particolarmente complessa, può contattarmi in qualsiasi momento sul sito Web www.ScriptingAnswers.com.

Don Jones collabora con TechNet Magazine come redattore ed è coautore del libro Windows PowerShell: TFM (SAPIEN Press). È docente di corsi su Windows PowerShell (www.ScriptingTraining.com) ed è possibile contattarlo dal sito Web ScriptingAnswers.com.

© 2008 Microsoft Corporation e CMP Media, LLC. Tutti i diritti riservati. È vietata la riproduzione completa o parziale senza autorizzazione.