Regular Expression (Parte II)
<< Leggi la prima parte dell'articolo
Lookaround
Lookaround è una funzionalità parzialmenteimplementata in JScript ma assente in VBScript. I lookaroundpossono essere di due direzioni, lookahead e lookbehind, peri quali si hanno due dichiarazioni ciascuna, una positiva eduna negativa. La sintassi relative ad ogni possibilecombinazione di questi 4 fattori è:
-
(?=...)
- Lookahead positivo -
(?!...)
- Lookahead negativo -
(?<=...)
- Lookbehind positivo -
(?<!...)
- Lookbehind negativo
Per capire il look(ahead|behind) c'è bisogno dicapire le differenze che intercorrono tra il trovare deltesto o il trovare delle posizioni. Bisogna infatti sapereche il puntatore (parser), una volta spostatosi per lastringa, non può tornare indietro a rieffettuare laricerca. Ciò può dar vita a difficoltà,se si considera ad esempio di voler trovare la parola"test" solamente se contenuta nella parola"tested" e non è contenuta in altre (peresempio, in "tester"). Con lookahead si puòinvece scrivere qualcosa del tipo (?=tested)test
,che funziona in quanto, grazie al lookaround, il parser nonviene sobbalzato per la stringa.Ciò può tornareutile soprattutto nel caso in cui si voglia trovare unaposizione nel domunento, combinando il lookahead ed illookbehind. Ed esempio, mettendo una negativa lookbehind sul"de" ed un positivo lookahead su "tested", del tipo:
(?<!de)(?=tested)test
In questo modo si troverà la posizione di partenza nelquale è stato trovato il testo.
Altro esempio di applicazione pratica del lookaround sono icontrolli su una password che richieda caratteristicheparticolari, come ad esempio almeno 2 lettere, 2 carattericomplessi ed un minimo di 8 caratteri per un massimo di 20.Per queste costrinzioni basta questa stringa:
^(?=.*?d.*?d)(?=.*?w.*?w)[dw]{8,20}$
Readability and Maintainability
Molto utile è la possibilità di inserire deicommenti nelle regular expressions. Non è difficileinfatti trovarsi difronte ad espressioni regolari complesse,del tipo
Dim re As New Regex( "(?<=(#|@))(?=w+)w+ " , RegexOptions.Multiline )
Nel migliore dei casi a precederle c'è unepigrafico commento che ne definisce gli intenti, ma ècomunque spesso troppo poco per permettere una rapidacomprensione del compito svolto. Fortunatamente il .NETpermette ora l' inserimento di commenti al loro interno,tramite il RegExOptions.IgnorePatternWhitespace
e usando la sintassi (?#...)
. Ecco un esempio:
Dim re As New Regex ( _ "(?<= (?# Inizia un lookBEHIND positivo ) " & _ "(#|@) (?# Ricerca un simbolo # o una @ ) " & _ ") (?# Chiude il lookBEHIND ) " & _ "(?= (?# Inizia un lookAHEAD positivo ) " & _ " w+(?# Ricerca almeno un carattere ) " & _ ") (?# Chiude il lookAHEAD ) " & _ "w+ (?# Ricerca )" , _ RegexOptions.Multiline Or RegexOptions.IgnoreCase Or RegexOptions.IgnoreWhitespace _)
Delegates
Infine, il .NET Framework ha introdotto il metodoRegex.Replace()
che permette di impostare untesto secondario da sostituire a quello trovato. Consideriamoil seguente snippet:
Dim myString As String = RegEx.Replace( "a true taste of the temperature" , "t.*?e" , "a" )
Questa espressione regolare ricerca una stringa nel testo e,una volta trovata, la sostituisce con il carattere"a". Esempio applicato può essere il volertrasformare tutte le lettere iniziali delle parole daminuscole a maiuscole. In questo caso lo schema sarà:
mc = re.Matches( bodyOfText )Dim m As MatchFor Each m In mc sb.AppendFormat("{0}{1}" , m.Groups(1).Value.ToUpper(), m.Groups(2).Value)Next
Con questo esempio però si può incappare inproblemi nel caso in cui la stringa contenga caratterispeciali, e sia del tipo ~~~ This %%% is ### a chunk oftext
; subito dopo la sostituzione alcuni caratterispeciali potrebbero scomparire, in quanto il replace nonriesce a sostituirli con la relativa maiuscola. Una soluzionepiù funzionale è invece usare unMatchEvaluator
che permette di eseguire unafunzione ogni volta che un' espressione viene trovata. Unesempio dimostrativo applicato all' esempio di prima:esegue la sostituzione e, nel caso non riesca a sostituireuna carattere speciale con una maiuscola (comeè ovvio che sia), re-inserisce il carattere speciale:
Sub Page_Load(sender as Object, e as EventArgs) Dim myDelegate As New MatchEvaluator( AddressOf MatchHandler ) Dim sb As New System.Text.Stringbuilder() Dim bodyOfText As String = _ "~~~ This %%% is ### a chunk of text."Dim pattern As String = "(w)(w+)?" Dim re As New Regex( _ pattern, RegexOptions.Multiline Or _ RegexOptions.IgnoreCase _ ) Dim newString As String = re.Replace(bodyOfText, myDelegate)Response.Write( bodyOfText & "<hr>" & newString )End SubPrivate Function MatchHandler( ByVal m As Match ) As String Return m.Groups(1).Value.ToUpper() & m.Groups(2).ValueEnd Function
Con l' inserimento di una funzione sperata, ma connessaalla regular expression, si da il la' ad espressionisempre più complesse che non perdono peròleggibilità e comprensibilità.
<< Leggi la prima parte dell'articolo
- Articolo precedente Regular Expression (Parte I)
- Articolo successivo Novitą e caratteristiche di ASP.NET 3.5: le principali nuove funzionalitą