Hey, Scripting Guy!Utilizzo delle espressioni regolari

Gli Scripting Guy di Microsoft

Scarica il codice per questo articolo: HeyScriptingGuy2008_05.exe (150KB)

Nel novembre del 2007, gli Scripting Guy hanno speso un giorno a Parigi mentre erano in viaggio per la conferenza Tech•Ed IT Forum che si sarebbe tenuta a Barcellona. Durante la nostra sosta di un giorno, abbiamo colto l'opportunità di visitare il Louvre, il museo d'arte di fama mondiale della città.

Come hanno trovato il Louvre gli Scripting Guy? La risposta è semplice: abbiamo camminato fino a Notre Dame e poi abbiamo svoltato a sinistra.

Oh, intendete dire che vi è piaciuto il museo? In linea di massima, sì. L'unico problema che abbiamo avuto è che nel Louvre, come in molti musei, vige la regola del "guardare ma non toccare". Tutti sanno che Monna Lisa avrebbe un aspetto migliore se avesse le sopracciglia, ma per qualche arcano motivo i gestori del Louvre si infuriano se qualcuno tenta di "ritoccare" un quadro.

Nota: in realtà, a noi Scripting Guy Monna Lisa è piaciuta molto. E questa è stata una piacevole sorpresa perché, dopo tutta la pubblicità a cui abbiamo assistito, temevamo che potesse essere soltanto un quadro come un altro. Ma non lo è stato. È molto bello! (Nonostante sarebbe meglio aggiungere le sopracciglia.) Sorprendentemente, tuttavia, entrambi siamo rimasti piuttosto delusi dall'altrettanto famosa Venere di Milo. Nessuno di noi ha trovato la scultura così spettacolare e lo Scripting Guy che sta scrivendo questo articolo è rimasto piuttosto perplesso dall'idea complessiva della Venere de Milo. Una statua di donna senza braccia? E come fa a spazzare il pavimento o a lavare i piatti!?!

Nota per le nostre lettrici donne (sperando che ce ne sia rimasta qualcuna): ovviamente la frase precedente non è stata formulata correttamente. In realtà volevamo dire questo: una statua di una donna senza braccia? Eppure è in grado di svolgere due volte il lavoro di qualunque uomo e di svolgerlo nel migliore dei modi!

Gli Scripting Guy si scusano per eventuali malintesi creati dalla nostra affermazione iniziale.

In ogni caso, dopo aver posato i loro occhi sui meravigliosi tesori del Louvre, i due Scripting Guy sono stati colpiti dallo stesso identico pensiero: dove sono i bagni? Durante la ricerca, lo Scripting Guy che scrive questo articolo è stato colpito da un altro pensiero: gli Scripting Guy sono ipocriti. Dopotutto, siamo seccati per il fatto che il Louvre non ci consentirà di ritoccare Monna Lisa. Eppure, anche noi abbiamo commesso un peccato simile. Nel numero del gennaio 2008 di TechNet Magazine, abbiamo scritto un articolo relativo all'utilizzo delle espressioni regolari in uno script. Tale script è un ottimo esempio della regola "guardare ma non toccare": abbiamo mostrato come utilizzare le espressioni regolari per identificare i problemi in un file di testo, ma non abbiamo spiegato come risolverli. Accidenti!

Nota: ma se gli Scripting Guy sono andati al Louvre nel novembre 2007, come è possibile che lo Scripting Guy che scrive questo articolo ha avuto un'illuminazione riguardante un articolo che è comparso in TechNet Magazine soltanto nel gennaio 2008? Wow! Si tratta di un indovinello, o no? Deve avere a che fare con le differenze di fuso orario tra Redmond e Parigi.

Fortunatamente, tuttavia, e a differenza dei gestori del Louvre, gli Scripting Guy sono disposti ad ammettere quando commettono un errore. Abbiamo sbagliato a mostrarvi soltanto come ricercare degli elementi tramite le espressioni regolari; avremmo dovuto spiegarvi come sostituire tali elementi utilizzando le espressioni regolari. In realtà, avremmo dovuto mostrarvi uno script come quello della Figura 1.

Figure 1 Ricerca e sostituzione

      Set objRegEx = _
    CreateObject("VBScript.RegExp")

objRegEx.Global = True   
objRegEx.IgnoreCase = True
objRegEx.Pattern = "Mona Lisa"

strSearchString = _
    "The Mona Lisa is in the Louvre."
strNewString = _
    objRegEx.Replace(strSearchString, _
                     "La Gioconda")

Wscript.Echo strNewString 

Ora, a dirvi il vero, questo è un uso piuttosto ordinario delle espressioni regolari: in questo caso, stiamo semplicemente sostituendo tutte le istanze del valore di stringa Mona Lisa con La Gioconda (traduzione italiana di "E ora dove sono finite quelle sopracciglia?"). Sinceramente, avremmo potuto eseguire questa sostituzione molto più facilmente utilizzando la funzione Replace di VBScript. Ma, non temete: utilizzeremo questo piccolo e semplice script per spiegare come eseguire le operazioni di ricerca e sostituzione utilizzando delle espressioni regolari e, in seguito, vi mostreremo alcune delle operazioni più elaborate che è possibile eseguire con queste espressioni.

Come si può vedere, lo script non è affatto elaborato. Iniziamo creando un'istanza dell'oggetto VBScript.RegExp, che ci consente di utilizzare le espressioni regolari in uno script VBScript. Dopo la creazione dell'oggetto, assegniamo dei valori a tre delle proprietà dell'oggetto:

Global Impostando questa proprietà su True, lo script ricercherà (e sostituirà) ogni istanza di Mona Lisa presente nel testo di destinazione. Se la proprietà Global fosse False (il valore predefinito), lo script ricercherebbe e sostituirebbe soltanto la prima istanza di Mona Lisa.

IgnoreCase Impostando IgnoreCase su True, lo script eseguirà una ricerca senza distinzione di maiuscole/minuscole; in altre parole, mona lisa e Mona Lisa verranno trattate nello stesso modo. Per impostazione predefinita, VBScript esegue una ricerca con distinzione di maiuscole/minuscole, il che significa che mona lisa e Mona Lisa vengono considerate dei valori completamente differenti.

Pattern La proprietà Pattern contiene il valore che stiamo cercando. In questo caso, stiamo ricercando soltanto un semplice valore di stringa: Mona Lisa.

In seguito, assegniamo il testo che vogliamo ricercare ad una variabile denominata strSearchString:

strSearchString = "The Mona Lisa is in the Louvre."

Poi chiamiamo il metodo di espressione regolare Replace, inviando a tale metodo due parametri: Il testo di destinazione che intendiamo ricercare (la variabile strSearchString) e il testo di sostituzione (La Gioconda). Ecco come si procede:

strNewString = objRegEx.Replace(strSearchString, "La Gioconda")

Ed ecco il risultato. Il testo modificato viene memorizzato nella variabile strNewString. Se ora eseguiamo un'istruzione echo di strNewString, otterremo il seguente risultato:

The La Gioconda is in the Louvre.

La grammatica è discutibile, ma si ottiene l'idea generale.

Come abbiamo indicato in precedenza, tutto ciò va benissimo, ma è eccessivo; avremmo potuto realizzare lo stesso identico risultato utilizzando queste righe di codice (in realtà, se avessimo voluto, avremmo potuto utilizzare anche una sola riga):

strSearchString = "The Mona Lisa is in the Louvre."
strNewString = Replace(strSearchString, "Mona Lisa", "La Gioconda")
Wscript.Echo strNewString

In altre parole, le espressioni regolari ci consentono di fare qualcosa che non è consentito con la funzione Replace in VBScript.

Vi state chiedendo cos'è questo "qualcosa"? Bene, intanto vi proponiamo un'idea. Spesso noi Scripting Guy finiamo per copiare il testo da un tipo di documento ad un altro. Talvolta questa pratica funziona, ma non è sempre così. Quando non funziona, ci ritroviamo a dover combattere con strani problemi di spaziatura tra parole, che generano un testo simile al seguente:

Myer Ken, Vice President, Sales and Services

Ahi ahi...guardate tutti quegli strani spazi! E, in questo caso, la funzione Replace è di scarso aiuto. Perché? Beh, ci troviamo di fronte ad un numero apparentemente casuale di spazi estranei: il numero di tali spazi è indefinito, il che rende difficile risolvere il problema tramite Replace. Ad esempio, se tentiamo di cercare 2 spazi consecutivi (sostituendoli con un unico spazio), finiamo per ottenere il seguente risultato:

Myer Ken, Vice President, Sales and  Services

È migliore, ma non perfetto. Esiste un modo per ottenere il risultato che stiamo cercando ma richiede la ricerca di un numero arbitrario di spazi (ad esempio, 39); la relativa sostituzione; la sottrazione di 1 dal numero iniziale, la ricerca di 38 spazi; la relativa sostituzione e così via. In alternativa, potremmo utilizzare questo script di espressioni regolari molto più semplice e infallibile:

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = " {2,}"

strSearchString = _
"Myer Ken, Vice President, Sales and Services"
strNewString = objRegEx.Replace(strSearchString," ")

Wscript.Echo strNewString

la chiave per questo script (e per la maggior parte degli script di espressioni regolari) è Pattern:

objRegEx.Pattern = " {2,}"

In questo esempio, si ricercano 2 o più spazi consecutivi. Come sappiamo che questo Pattern ricerca 2 o più spazi? Dunque...nei nostri contrassegni con doppi apici è presente un singolo spazio seguito da questo costrutto: {2,}. Nella sintassi di espressioni regolari, ciò indica di ricercare almeno 2 istanze consecutive del carattere precedente (in questo caso, uno spazio). E come fare in presenza di 3, 4 o 937 spazi consecutivi? Nessun problema. Verranno rilevati comunque. (Se, per qualche ragione, volessimo individuare almeno 2 ma al massimo 8 spazi, utilizzeremmo la sintassi {2,8}, in cui 8 specifica il numero massimo di corrispondenze).

In altre parole, ogni volta che vengono rilevati 2 o più spazi, tutti gli spazi consecutivi verranno sostituiti con un singolo spazio. Cosa succederà al nostro valore di stringa originale, con tutti gli spazi? Questo:

Myer Ken, Vice President, Sales and Services

Visto? Gli Scripting Guy possono realmente migliorare le cose. Se solo i gestori del Louvre ci consentissero di ritoccare Monna Lisa...

Di seguito viene riportato un interessante scenario piuttosto insolito. Supponiamo che la vostra azienda abbia un elenco telefonico in cui tutti i numeri hanno il seguente formato:

555-123-4567

Ora, il vostro capo ha deciso che tutti i numeri di telefono dovranno avere il seguente formato:

(555) 123-4567

Come fare per modificare il formato di tali numeri? Potremmo essere così audaci da suggerirvi di utilizzare uno script simile al seguente:

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "(\d{3})-(\d{3})-(\d{4})"

strSearchString = "555-123-4567"
strNewString = objRegEx.Replace _
(strSearchString, "($1) $2-$3")

Wscript.Echo strNewString

In questo esempio stiamo cercando 3 cifre (\d{3}) seguite da un trattino, seguite da altre 3 cifre e da un trattino, seguiti da 4 cifre. In altre parole, stiamo cercando il seguente schema, in cui ogni X rappresenta un numero da 0 a 9:

XXX-XXX-XXXX

Nota: come potevamo sapere che \d{3} avrebbe consentito allo script di ricercare tre numeri a ritroso? Per quanto possiamo ricordarci, lo abbiamo letto da qualche parte. Forse nello scioccante capitolo finale del Codice da Vinci o nel VBScript Language Reference di MSDN® online (vedere go.microsoft.com/fwlink/?LinkID=111387).

A questo punto, è fantastico poter ricercare un numero di telefono arbitrario utilizzando le espressioni regolari. Tuttavia, resta ancora un problema fondamentale da risolvere. Dopotutto, non possiamo sostituire tale numero di telefono arbitrario con un numero di telefono ugualmente arbitrario, ma dobbiamo usare lo stesso numero di telefono con un formato leggermente diverso. Come fare?

Utilizzando il seguente testo di sostituzione:

"($1) $2-$3"

$1, $2 e $3 sono degli esempi di un'espressione un regolare "con riferimento all'indietro". Un riferimento all'indietro è semplicemente una parte del testo trovato che può essere salvata e riutilizzata. In questo specifico script, stiamo ricercando tre corrispondenze secondarie:

  • Una serie di 3 cifre
  • Una serie di altre 3 cifre
  • Una serie di 4 cifre

A ciascuna di tali corrispondenze secondarie viene assegnato automaticamente un riferimento all'indietro: la prima corrispondenza secondaria è $1; la seconda è $2 e così via, fino a $9. In altre parole, questo script assegna automaticamente alle tre parti del nostro numero di telefono i riferimenti all'indietro mostrati nella Figura 2.

Figure 2 Riferimenti all'indietro nei numeri di telefono

Parte del numero di telefono Riferimento all'indietro
555 $1
123 $2
4567 $3

Nella nostra stringa di sostituzione, abbiamo usato tali riferimenti all'indietro per garantire il possibile riutilizzo del numero di telefono. Il nostro testo di sostituzione indica semplicemente questo: prendere il primo riferimento all'indietro ($1) e includerlo fra parentesi. Lasciare uno spazio e inserire il secondo riferimento all'indietro ($2) seguito da un trattino. Infine, aggiungere il terzo riferimento all'indietro ($3).

Quale sarà il risultato? Un numero di telefono simile al seguente:

(555) 123-4567

Niente male.

Di seguito viene riportata una variazione allo script dei numeri di telefono. Supponiamo che la vostra organizzazione abbia installato un nuovo sistema telefonico e che, in seguito al cambiamento, tutti i numeri di telefono hanno ora lo stesso prefisso; tutti i numeri che iniziavano originalmente con 666, 777 o 888 iniziano ora con 333. Possiamo riformattare contemporaneamente tali numeri e modificarne il prefisso? Ovviamente sì.

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "(\d{3})-(\d{3})-(\d{4})"

strSearchString = "555-123-4567"
strNewString = objRegEx.Replace _
(strSearchString,"($1) 333-$3")

Wscript.Echo strNewString

Ecco come abbiamo ottenuto questo risultato: abbiamo rimosso il vecchio prefisso (il riferimento all'indietro $2) nel nostro testo di sostituzione; al suo posto abbiamo inserito il valore di prefisso codificato e standard 333. Come apparirà il numero 555-123-4567 dopo l'esecuzione di questo script modificato? Apparirà come riportato nel seguente esempio:

(555) 333-4567

Di seguito viene riportato un altro uso comune del riferimento all'indietro. Supponiamo la presenza di un valore di stringa simile al seguente:

Myer, Ken

Esiste un modo per modificare tale valore e visualizzare il nome nel modo seguente?

Ken Myer

Appariremmo piuttosto stupidi se la risposta fosse no, giusto? Ecco uno script che consente di ottenere esattamente il risultato desiderato:

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "(\S+), (\S+)"

strSearchString = "Myer, Ken"
strNewString = objRegEx.Replace _

strSearchString,"$2 $1")

Wscript.Echo strNewString

In questo specifico script, stiamo cercando una parola, (\S+), seguita da una virgola, seguita da uno spazio, seguito da un'altra parola. (In questo caso, utilizziamo \S+ per indicare una parola). Il valore \S+ indica qualsiasi serie consecutiva di caratteri diversi da uno spazio. In altre parole, tale valore può rappresentare una lettera, un numero, un simbolo, purché sia un carattere diverso da uno spazio, una tabulazione, un ritorno a capo o un avanzamento riga. Come potrete notare, ci aspettiamo di trovare due corrispondenze secondarie in questo caso: una che rappresenti il cognome ($1) e una che rappresenti il nome ($2). Di conseguenza, possiamo visualizzare il nome utente come FirstName LastName tramite la seguente sintassi:

"$2 $1"

Dov'è la virgola? In realtà, non ne avevamo bisogno e l'abbiamo semplicemente tolta.

Nota: è divertente che, per qualche motivo, abbiamo iniziato a pensare anche all'editor di script. Hmmm...

Desideriamo mostrarvi un altro esempio o prima di chiudere. Non si tratta di un esempio infallibile al 100%; dopo tutto, non vogliamo che un articolo introduttivo come questo diventi troppo complicato. (E le espressioni regolari hanno il potenziale di diventare estremamente complicate). Tuttavia, ecco uno script che, nella maggior parte dei casi, rimuoverà gli zero iniziali da un valore come 0000,34500044:

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "\b0{1,}\."

strSearchString = _
"The final value was 0000.34500044."
strNewString = objRegEx.Replace _
strSearchString,".")

script.Echo strNewString

Come al solito, l'unico motivo per cui lo script funziona è per il modello: "\b0{1,}\." Iniziamo con il ricercare un vincolo di parola (\b); che garantisca che non vengano rimossi gli zero in un valore quale, ad esempio, 100,546. Ricercheremo poi uno o più zero, 0{1,}, seguiti da una virgola decimale (\,). Se il modello viene rilevato, gli zeri e la virgola decimale vengono sostituiti da una singola virgola decimale ",". Se tutto procede secondo il piano, la nostra stringa verrà convertita nel seguente modo:

The final value was .34500044.

È tutto per questo mese. Prima di chiudere, potremmo sottolineare che, mentre il quadro era ancora in esecuzione, la Monna Lisa divenne l'oggetto di una notevole controversia. Chi è la donna misteriosa? Perché sorride in quel modo? Perché non ha le sopracciglia? Diversi storici d'arte sostengono che Monna Lisa in realtà non era neanche una donna e che il ritratto non è niente altro che l'autoritratto di Leonardo da Vinci. (Se fosse vero, Leonardo avrebbe potuto trovare un sarto migliore). Nel frattempo, la Unarius Educational Foundation è andata ancora oltre, sostenendo che il dipinto è in realtà quello dell'anima gemella di Leonardo e che tale anima del "mondo superiore" avrebbe guidato la mano di Leonardo. Per una stranissima coincidenza, questo è esattamente il modo in cui è stato scritto l'articolo di Hey, Scripting Guy! di questo mese.

Il che significa che le eventuali lamentele potranno essere inviate all'indirizzo the-twin-soul-of-the-scripting-guy-who-writes-that-column@the-other-microsoft.com. Grazie!

Il rompicapo di script del Dottor Scripto

La sfida mensile che verifica non solo le tue capacità di risoluzione dei puzzle, ma anche le tue competenze di scripting.

Maggio 2008: Script-doku

Questo mese, giochiamo a Sudoku, ma con una lieve modifica. Al posto dei numeri dall'1 al 0 nella griglia, sono presenti le lettere e i simboli che compongono un cmdlet Windows PowerShell™. Nella soluzione finale, una delle righe riporterà il nome di cmdlet.

Nota: per tutti coloro che non sanno giocare a Sudoku, consigliamo di consultare uno delle diverse migliaia di siti Web contenenti le istruzioni che, siamo spiacenti, non verranno ripetute in questo articolo.

ANSWER:

Il rompicapo di script del Dottor Scripto

Risposta: Script-doku, maggio 2008

Gli Scripting Guy di Microsoft lavorano o, per meglio dire, sono stipendiati da Microsoft. Quando non si dedicano al baseball (o ad altre attività) come giocatori, allenatori o semplici spettatori, gestiscono il TechNet Script Center. Consultare la pagina www.scriptingguys.com.

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