asp - asp.net - aspcode.it

COMMUNITY - Login
 Username:
 
 Password:
 
Voglio registrarmi!
Password dimenticata?
 Utenti on-line: 0
 Ospiti on-line: 1209
ASPCode.it - Store

  > > Articoli

Controllo lessicale server-side di un indirizzo email

Data di pubblicazione: 11/12/2002        Voto della community: 4,85 (Votanti: 9)


Lo scopo di questo articolo è di fornire due diverse implementazioni della stessa funzione VBScript che controlla la validità lessicale di un indirizzo email. Si tratta di un'operazione molto comune e necessaria, ad esempio, quando utilizziamo un form di iscrizione ad una newsletter (...a quella di ASPCode.it tutti dovrebbero essere iscritti!!!). Tale verifica lessicale può essere effettuata sia lato client tramite JavaScript sia lato server sfruttando le tecnologie ASP, PHP, CGI, ecc... Sarà proprio quest'ultima, quella server-side, la strada che seguiremo.

Dobbiamo dire che, ormai, il problema della validità lessicale di un indirizzo email è stato analizzato e risolto in molti modi e a vari livelli e certo questo articolo non aggiunge nulla di nuovo sull'argomento. Tuttavia, l'analisi che faremo mostra come la soluzione "classica" possa essere implementata in modo diverso sfruttando il versatile e potente strumento delle espressioni regolari (ER). Le ER sono supportate in modo nativo dai linguaggi di scripting targati Microsoft (prima JScript e VBScript ver. 5 ed ora anche dall'ambiente .NET).

La soluzione "classica"

Un indirizzo email è semplicemente una stringa di caratteri alfanumerici opportunamente concatenati. Ad esempio asp@code.it è un indirizzo email corretto dal punto di vista lessicale (...ma non necessariamente nella semantica). Di conseguenza, i controlli lessicali sui caratteri usati e sulla loro posizione, si possono facilmente implementare sfruttando le funzioni che manipolano le stringhe di testo.

La seguente funzione VBScript scompone la stringa di testo dell'email in 2 sottostringhe (il carattere chiocciola '@' è lo spartiacque) sulle quali effettuare verifiche di tipo dimensionale (lunghezza) e di tipo alfabetico (caratteri usati).

<%
Function CheckEmail(str)

  ' Dichiarazione delle variabili
  Dim i, j, first, last, char

  ' Controlli di tipo dimensionale

  ' posizione del carattere '@'
  i = instr(str, "@")
  if (i > 0) and (i < len(str)) then
    ' testo che precede '@'
    first = left(str, i - 1)
    ' testo che segue '@'
    last = mid(str, i+1, len(str))
  else
    CheckEmail = false
    exit function
  end if

  ' almeno 1 carattere PRIMA di '@'
  if (len(first) = 0) then
    CheckEmail = false
    exit function
  end if

  ' posizione dell'ultimo carattere '.'
  i = instrrev(last, ".")

  ' almeno 1 carattere DOPO '@' e PRIMA dell'ultimo '.'
  if len(mid(last,1,i)) = 0 then
    CheckEmail = false
    exit function
  end if

  ' suffisso finale è lungo 2 o 3 caratteri
  j = len(last) - i
  if (j <= 1) or (j >= 4) then
    CheckEmail = false
    exit function
  end if

  ' Controlla i caratteri PRIMA di '@'
  i = 0
  do until (i = len(first))
    i = i + 1
    char = mid(first, i, 1)

    ' caratteri leciti sono [a-zA-Z0-9_.-]
    if (asc(char) <> 45) and (asc(char) <> 46) and _
      (asc(char) < 48 or asc(char) > 57) and _
      (asc(char) < 65 or asc(char) > 90) and _
      (asc(char) <> 95) and _
      (asc(char) < 97 or asc(char) > 122) then

      CheckEmail = false
      exit function
    end if
  loop

  ' Controlla i caratteri DOPO la '@'
  i = 0
  do until i = len(last)
    i = i + 1
    char = mid(last, i, 1)

    ' caratteri leciti sono [a-zA-Z0-9_.-]
    if (asc(char) <> 45) and (asc(char) <> 46) and _
      (asc(char) < 48 or asc(char) > 57) and _
      (asc(char) < 65 or asc(char) > 90) and _
      (asc(char) <> 95) and _
      (asc(char) < 97 or asc(char) > 122) then

      CheckEmail = false
      exit function
    end if
  loop

  ' Email adesso è valida...
  ' dopo tutti questi controlli !!!

  CheckEmail = true

End Function
%>

L'alternativa ER

La seconda soluzione ricalca la logica seguita nella prima funzione, però sfrutta la potenza e la versatilità delle espressioni regolari. Le ER consentono di semplificare e ridurre notevolmente il codice VBScript da scrivere, rendendo così la funzione più compatta, più leggibile e di più facile manutenzione.

Non è questa la sede per spiegare la teoria sulle ER (vedi questo articolo) ma basti sapere che di solito vengono adoperate per manipolare stringhe di testo, perché permettono di ricercare o sostituire velocemente (in inglese, eseguire pattern matching) una sequenza o sottostringa di caratteri all'interno di una stringa più grande.

Applichiamo, dunque, le ER per controllare la validità lessicale del nostro indirizzo email:

<%
Function CheckEmail(str)

  Dim objER, result

  ' istanzia l'oggetto REGULAR EXPRESSION
  Set objER = New RegExp

  ' cerca il pattern in tutta la stringa di input
  objER.Global = True

  ' nessuna differenza fra maiuscole/minuscole
  objER.IgnoreCase = True

  '''''''''''''''''''''''''''''''''''''''''''''''''
  objER.Pattern = "^[\w\.-]+@[\w\.-]+\.[a-z]{2,3}$"
  '''''''''''''''''''''''''''''''''''''''''''''''''

  ' verifica la corrispondenza con il pattern
  result = objER.Test(str)

  Set objER = Nothing
  CheckEmail = result

End Function
%>

Il cuore della funzione è costituito dalla dichiarazione del pattern della ER, ossia dalla stringa "^[\w\.-]+@[\w\.-]+\.[a-z]{2,3}$". La sintassi all'inizio è un po' ostica da imparare e quindi da usare, ma è evidente come riesca a riassumere in poco spazio una grande quantità di informazioni... Ecco, infatti, l'interpretazione del significato associato al pattern:

^
Il simbolo elevamento a potenza '^' indica che cerchiamo la corrispondenza a partire dall'inizio della stringa passata in input. Tale corrispondenza si riferisce alla sotto-espressione (nel nostro caso [\w\.-]+) che segue il simbolo '^' elevamento a potenza.

[\w\.-]+
Le parentesi quadre descrivono un insieme finito di caratteri. L'espressione '\w' è una abbreviazione di '[A-Za-z0-9_]' che denota tutti i caratteri alfanumerici, compreso l'underscore. L'espressione '\.' aggiunge all'insieme anche il carattere punto, con la particolarità che il punto '.' è preceduto dal backslash perché è un meta-carattere. L'espressione '-' aggiunge all'insieme di partenza anche il carattere meno. Il simbolo finale '+' dice che la precedente sotto-espressione (le parentesi quadre) deve essere considerata 1 o più volte.

@
Il carattere chiocciola '@' deve trovarsi esattamente in questa posizione.

[\w\.-]+
Descrive l'insieme dei caratteri alfanumerici, l'underscore, il punto ed il meno ripetuti almeno 1 volta.

\.
Il carattere punto '.' deve trovarsi in questa posizione. Il punto è un meta-carattere, quindi serve il backslash per essere considerato come un carattere normale.

[a-z]{2,3}
Questa scrittura dice che sono presenti almeno 2 e non più di 3 caratteri alfabetici.

$
Il simbolo dollaro '$' indica che stiamo cercando la corrispondenza alla fine della stringa passata come input e tale corrispondenza si riferisce alla sotto-espressione (nel nostro caso [a-z]{2,3}) che precede il simbolo dollaro '$'.

Conclusione

Giunti a questo punto, siamo in grado di capire meglio quanto possano essere potenti le ER. In effetti, nella seconda implementazione della nostra funzione abbiamo inglobato in una sola stringa di testo (il pattern) tutte le istruzioni di controllo, verifica e test, nonché tutti i cicli presenti nel corpo della prima!

Tuttavia, il pattern della seconda funzione può essere ancora migliorato, tramite una stringa più complessa, per effettuare ulteriori controlli (ad esempio, provate con la stringa "^[\w\-\.]*[\w\.]\@[\w\.]*[\w\-\.]+[\w\-]+[\w]\.+[\w]+[\w $]")

Dovrebbe anche essere chiaro che le ER possono essere applicate a situazioni molto diverse da quella che abbiamo considerato in questo articolo. Semplicemente utilizzando altri pattern sarebbe possibile verificare un CAP, un codice fiscale, un numero di cellulare, ecc. Basta scrivere la giusta sintassi nel pattern e l'oggetto ER della seconda funzione si preoccuperà di eseguire tutto il lavoro per noi, con algoritmi interni ottimizzati e risparmiandoci linee e linee di codice sorgente!

Tempi di elaborazione

Animato da spirito di pura curiosità ho testato la performance delle 2 precedenti funzioni su un campione di 500 indirizzi email. Per terminare l'analisi lessicale ho constatato che la seconda funzione (quella con le famose ER) ha impiegato circa 0.6 secondi mentre la prima funzione (quella che processa le stringhe di testo) circa 0.3 secondi cioè esattamente la metà del tempo! Questo risultato sembra essere un punto a sfavore delle ER, cioè tempi di elaborazione decisamente più lunghi nel caso di grossi carichi di lavoro. La realtà però è ben diversa, come testimonia l'intelligente segnalazione di un attento lettore (Antonio del Pozzo) che così scrive:
"Ciò che trae in inganno è il fatto che l'oggetto RegExp è creato ogni volta per ogni e-mail. Basta creare l'oggetto RegExp una sola volta fuori dalla funzione e poi richiamarlo all'interno della stessa. In questo modo la valutazione della performance cambia."
Il lettore ha pienamente ragione, perchè una percentuale consistente di quei 0.6 secondi dipende proprio dal tempo necessario alla creazione/distruzione dell'oggetto RegExp ogni volta che si invoca la seconda funzione. Seguendo codesto "modus operandi" ecco che i tempi di elaborazione diminuiscono drasticamente, infatti ora la seconda funzione (opportunamente modificata) impiega meno di 0.1 secondi per controllare la lista di 500 indirizzi email. In definitiva quindi, l'utilizzo intelligente delle ER si rivela non solo una soluzione potente ed elegante, ma anche molto performante !!!




Utenti connessi: 1209