c# character expressions - utilizzando Regex.IsMatch statico o creando un'istanza di Regex




4 Answers

In un raro allontanamento dal mio tipico egotismo, sono quasi invertire questa mia risposta.

La mia risposta originale, conservata di seguito, era basata su un esame della versione 1.1 del framework .NET. Questo è piuttosto vergognoso, dal momento che .NET 2.0 era uscito da più di tre anni al momento della mia risposta e conteneva modifiche alla classe Regex che incidono significativamente sulla differenza tra i metodi statici e di istanza.

In .NET 2.0 (e 4.0), la funzione IsMatch statica è definita come segue:

public static bool IsMatch(string input, string pattern){
    return new Regex(pattern, RegexOptions.None, true).IsMatch(input);
}

La differenza significativa qui è quella piccola true come il terzo argomento. Ciò corrisponde a un parametro denominato "useCache". Quando ciò è vero, l'albero analizzato viene recuperato dalla cache sul secondo e successivo utilizzo.

Questa memorizzazione nella cache consuma la maggior parte, ma non tutte, le differenze di prestazioni tra i metodi statici e di istanza. Nei miei test, il metodo statico di IsMatch era ancora circa il 20% più lento del metodo di istanza, ma questo ammontava a circa mezzo secondo di incremento se eseguito 100 volte su un set di 10.000 stringhe di input (per un totale di 1 milione di operazioni).

Questo rallentamento del 20% può ancora essere significativo in alcuni scenari. Se ti ritrovi a scrivere centinaia di milioni di stringhe, probabilmente vorrai fare ogni passo possibile per renderlo più efficiente. Ma scommetterei che il 99% delle volte, stai usando un Regex particolare non più di una manciata di volte, e il millisecondo in più che perdi con il metodo statico non sarà nemmeno vicino a quello visibile.

Puntelli su devgeezer , che lo ha sottolineato quasi un anno fa, anche se nessuno sembrava accorgersene.

La mia vecchia risposta segue:

La funzione IsMatch statica è definita come segue:

public static bool IsMatch(string input, string pattern){
    return new Regex(pattern).IsMatch(input);
}

E, sì, l'inizializzazione di un oggetto Regex non è banale. È necessario utilizzare l' IsMatch statico (o qualsiasi altra funzione statica di Regex ) come collegamento rapido solo per i pattern che verranno utilizzati una sola volta. Se riutilizzerai il pattern, vale la pena di riutilizzare anche un oggetto Regex .

Riguardo all'opportunità o meno di specificare RegexOptions.Compiled , come suggerito da Jon Skeet, questa è un'altra storia. La risposta è: dipende. Per i pattern semplici o per i pattern usati solo una manciata di volte, potrebbe essere più veloce usare un'istanza non compilata. Dovresti assolutamente definire il profilo prima di decidere. Il costo della compilazione di un oggetto di espressione regolare è piuttosto grande e potrebbe non valerne la pena.

Prendi, ad esempio, quanto segue:

const int count = 10000;

string pattern = "^[a-z]+[0-9]+$";
string input   = "abc123";

Stopwatch sw = Stopwatch.StartNew();
for(int i = 0; i < count; i++)
    Regex.IsMatch(input, pattern);
Console.WriteLine("static took {0} seconds.", sw.Elapsed.TotalSeconds);

sw.Reset();
sw.Start();
Regex rx = new Regex(pattern);
for(int i = 0; i < count; i++)
    rx.IsMatch(input);
Console.WriteLine("instance took {0} seconds.", sw.Elapsed.TotalSeconds);

sw.Reset();
sw.Start();
rx = new Regex(pattern, RegexOptions.Compiled);
for(int i = 0; i < count; i++)
    rx.IsMatch(input);
Console.WriteLine("compiled took {0} seconds.", sw.Elapsed.TotalSeconds);

A count = 10000 , come elencato, la seconda uscita è la più veloce. Aumenta il count a 100000 e la versione compilata vince.

pattern vb

In C # dovresti avere un codice come:

public static string importantRegex = "magic!";

public void F1(){
  //code
  if(Regex.IsMatch(importantRegex)){
    //codez in here.
  }
  //more code
}
public void main(){
  F1();
/*
  some stuff happens......
*/
  F1();
}

o dovresti persistere un'istanza di un Regex contenente lo schema importante? Quanto costa utilizzare Regex.IsMatch? Immagino ci sia un NFA creato in ogni intento Regex. Da quello che ho capito, questa creazione NFA non è banale.




Questa risposta non è più corretta per quanto riguarda le versioni di .NET che ho sulla mia macchina. 4.0.30319 e 2.0.50727 hanno entrambi i seguenti elementi per IsMatch:

public static bool IsMatch(string input, string pattern)
{
  return new Regex(pattern, RegexOptions.None, true).IsMatch(input);
}

Il valore 'true' è per un parametro costruttore chiamato "useCache". Tutti i costruttori del Regex alla fine attraversano questo, gli statici chiamano questo direttamente - passando in "vero".

Leggi di più sul post del blog BCL sull'ottimizzazione delle prestazioni di Regex evidenziando l'uso della cache dei metodi statici here . Questo post del blog cita anche le misurazioni delle prestazioni. La lettura di serie di post su come ottimizzare le prestazioni di Regex è un ottimo punto di partenza.




Ci sono molte cose che influenzano le prestazioni dell'uso di un'espressione regolare. In definitiva, l'unico modo per scoprire il più performante nella tua situazione è misurare, usando la situazione più realistica possibile.

La pagina sulla compilazione e il riutilizzo di oggetti di espressioni regolari su MSDN copre questo. In sintesi, dice

  1. Le espressioni regolari compilate richiedono tempo per essere compilate e, una volta compilate, la loro memoria verrà scaricata solo su AppDomain . Se si debba usare la compilazione o meno dipenderà dal numero di modelli che si stanno utilizzando e dalla frequenza con cui vengono utilizzati.

  2. I metodi statici di Regex memorizzano nella cache la rappresentazione dell'espressione regolare analizzata per gli ultimi 15 (di default) dei modelli. Quindi, se non si utilizzano molti modelli diversi nella propria applicazione o se il proprio utilizzo è sufficientemente cluster, non ci sarà molta differenza tra il caching dell'istanza o il framework che lo memorizza nella cache.




Per un'applicazione WinForm su cui stavo lavorando, potremmo definire un'espressione regolare su caratteri validi che verrebbero eseguiti su ogni sequenza di tasti e una convalida per il testo per qualsiasi casella di testo (applicazione di immissione dati), quindi ho usato una cache o espressioni regolari come

  private static Dictionary<string, Regex> regexCache = new Dictionary<string, Regex>(20);

Dove l'espressione regex era la chiave.

Poi ho avuto una funzione statica che potrei chiamare durante la convalida dei dati:

public static bool RegExValidate(string text, string regex)
{
  if (!regexCache.ContainsKey(regex))
  {
    Regex compiledRegex = new Regex(regex,RegexOptions.Compiled);
    regexCache.Add(regex, compiledRegex);
  }
  return regexCache[regex].IsMatch(text);
}



Related