TOC

This article is currently in the process of being translated into Italian (~99% done).

Regular Expressions (Regex):

Search/Replace with the Regex Class

Abbiamo già parlato della classe Regex e di come utilizzarla quando si vuole effettuare una ricerca in una stringa in un articolo precedente. Le Regular Expressions sono ottime per questo, ma un altro utilizzo si ha quando si vogliono eseguire operazioni di ricerca/sostituzione, in cui si vuole cercare uno schema specifico e sostituirlo con qualcos'altro. La classe String ha già un metodo Replace(), ma è utile solo per effettuare ricerche semplici. Quando si utilizzano le Regular Expressions, è possibile sfruttare la potenza delle ricerche regex e persino utilizzare gruppi catturati come parte della stringa di sostituzione. Sembra complicato? Non preoccupatevi, inizieremo con un semplice esempio e poi pian piano ci avvicineremo a casi d'uso più avanzati.

Come nell'articolo precedente, tutti gli esempi presuppongono che sia stato importato il namespace RegularExpressions, in questo modo:

using System.Text.RegularExpressions;

Con queste premesse, proviamo a lavorare con la sostituzione di stringhe basata sulle espressioni regolari. Utilizzeremo il metodo Replace() della classe Regex:

string testString = "<b>Hello, <i>world</i></b>";
Regex regex = new Regex("<[^>]+>");
string cleanString = regex.Replace(testString, "");
Console.WriteLine(cleanString);

Questo esempio mostra un approccio molto semplificato alla rimozione dei tag HTML da una stringa. Si abbina tutto ciò che è circondato da una serie di parentesi angolari (<>) e si usa il metodo Replace() per sostituire ogni occorrenza con una stringa vuota, rimuovendo in pratica i tag HTML dalla stringa di test.

Sostituzione con valori acquisiti

Ma supponiamo di non volerli rimuovere, bensì di voler trasformare i tag in qualcosa che non venga interpretato dal browser, ad esempio sostituendo le parentesi angolari (<>) con parentesi quadre ([]). È qui che le Regular Expressions mostrano la loro potenza, perché è molto semplice, come illustrato da questa versione leggermente riscritta del nostro esempio precedente:

string testString = "<b>Hello, <i>world</i></b>";
Regex regex = new Regex("<([^>]+)>");
string cleanString = regex.Replace(testString, "[$1]");
Console.WriteLine(cleanString);

In realtà ho modificato solo due dettagli minori: Ho aggiunto una serie di parentesi alla regex, per creare un gruppo di cattura, catturando essenzialmente il valore tra le parentesi angolari nel primo gruppo di cattura. Nel metodo Replace() faccio riferimento a questo valore usando la notazione speciale $1, che in pratica significa solo il gruppo di cattura numero 1. Con questo metodo, il nostro output sarà ora simile a questo:

[b]Hello, [i]world[/i][/b]

Gruppi di acquisizione denominati

Naturalmente è possibile fare la stessa cosa quando si usano i gruppi di cattura con nome (di cui si è parlato nell'articolo precedente), come in questo caso:

string testString = "<b>Hello, <i>world</i></b>";
Regex regex = new Regex("<(?<tagName>[^>]+)>");
string cleanString = regex.Replace(testString, "[${tagName}]");
Console.WriteLine(cleanString);

Quando si usano gruppi di cattura denominati, basta usare la notazione ${nome del gruppo di cattura}.

Utilizzo del metodo MatchEvaluator

Ma se si vuole avere un controllo ancora maggiore sul modo in cui il valore viene sostituito? A questo scopo, possiamo usare un parametro MatchEvaluator: in pratica, si tratta di un riferimento (delegato) a un metodo che verrà chiamato ogni volta che si deve effettuare una sostituzione, consentendo di modificare il valore di sostituzione prima che venga utilizzato. Riprendiamo l'esempio dei tag HTML che abbiamo già utilizzato un paio di volte, ma questa volta abbiamo il controllo su quali tag HTML vengono utilizzati. Ecco l'esempio completo:

using System;
using System.Text.RegularExpressions;

namespace RegexSearchReplaceMethod
{
    class Program
    {
static void Main(string[] args)
{
    string testString = "<b>Hello, <i>world</i></b>";
    Regex regex = new Regex("<(?<tagName>[^>]+)>");
    string cleanString = regex.Replace(testString, ProcessHtmlTag);
    Console.WriteLine(cleanString);
}

private static string ProcessHtmlTag(Match m)
{
    string tagName = m.Groups["tagName"].Value;
    string endTagPrefix = "";
    if(tagName.StartsWith("/"))
    {
endTagPrefix = "/";
tagName = tagName.Substring(1);
    }
    switch (tagName)
    {
case "b":
    tagName = "strong";
    break;
case "i":
    tagName = "em";
    break;
    }
    return "<" + endTagPrefix + tagName.ToLower() + ">";
}
    }
}

La prima parte dell'esempio è identica a quello precedente, ma invece di fornire una stringa di sostituzione, passiamo un riferimento al nostro metodo ProcessHtmlTag(). Come già detto, questo metodo viene richiamato ogni volta che sta per essere effettuata una sostituzione, con la corrispondenza in questione come parametro. Ciò significa che nel nostro metodo MatchEvaluator abbiamo tutte le informazioni sulla corrispondenza, in modo da poter agire di conseguenza. In questo caso, sfruttiamo questa opportunità per rendere i tag più semantici, sostituendo il tag bold (b) con un tag strong e il tag italic (i) con un tag emphasis (em). Indipendentemente dal fatto che il tag sia cambiato o meno, lo trasformiamo in minuscolo.

L'uso di un parametro MatchEvaluator è ovviamente molto potente e questo è solo un semplice esempio di ciò che si può ottenere.

Riepilogo

Le operazioni di ricerca/sostituzione diventano molto potenti quando si usano le Regular Expressions e ancora di più quando si usa il parametro MatchEvaluator, dove le possibilità di manipolazione delle stringhe diventano quasi infinite.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!