2012-01-20 17 views
6

Ho in classe circa 100 chiamate Regex, ogni chiamata copre diversi tipi di dati nel protocollo di testo, ma ho molti file e basato sull'analisi regex ha preso l'88% di esecuzione del mio codice.Sostituzione più veloce per Regex

molti questo tipo di codice:

{ 
    Match m_said = Regex.Match(line, @"(.*) said,", RegexOptions.IgnoreCase); 
    if (m_said.Success) 
    { 
    string playername = ma.Groups[1].Value; 
    // some action 
    return true; 
    } 
} 

{ 
    Match ma = Regex.Match(line, @"(.*) is connected", RegexOptions.IgnoreCase); 
    if (ma.Success) 
    { 
    string playername = ma.Groups[1].Value; 
    // some action 
    return true; 
    } 
} 
{ 
    Match ma = Regex.Match(line, @"(.*): brings in for (.*)", RegexOptions.IgnoreCase); 
    if (ma.Success) 
    { 
    string playername = ma.Groups[1].Value; 
    long amount = Detect_Value(ma.Groups[2].Value, line); 
    // some action 
    return true; 
    } 
} 

sia un modo per sostituire Regex con qualche altra soluzione più veloce?

+1

Penso che dipenda dal tipo di regex che stai usando ... fornisci alcuni campioni! –

risposta

8

Per espressioni regolari che vengono testati in loop, è spesso più veloce di precompilare loro al di fuori del ciclo e solo prova li all'interno del ciclo.

È necessario dichiarare le diverse espressioni regolari in primo luogo con i rispettivi modelli e chiamare il Match() solo con il testo da testare in un secondo passaggio.

+1

La classe RegEx non ha una cache? –

+0

@HenkHolterman: Infatti. L'ho appena verificato nel documento (Sono più abituato a PCRE che non fornisce un meccanismo di cache.) La cache dovrebbe funzionare per le chiamate statiche 'Regex.Match()' fatte dall'OP. Oppure ci sono troppe espressioni regolari in gioco e 'Regex.CacheSize' è un percorso da esplorare per migliorare le prestazioni (ma dubito)? – Seki

+0

Grazie, l'uomo lavora 10 volte più veloce ;-)))) – Svisstack

1

Si potrebbe provare a compilare il Regex in anticipo o prendere in considerazione che unisce tutte le singole espressioni Regex in uno (mostro) Regex:

Match m_said = Regex.Match(line, 
      @"(.*) (said|(is connected)|...|...),", 
      RegexOptions.IgnoreCase); 

Sarà quindi possibile testare il secondo gruppo di cattura per determinare quale tipo di partita si è verificato.

+0

Questa è l'unica risposta che vedo che tenta di scansionare il file (s) solo una volta. –

+0

A seconda dei possibili testi, potrebbe esserci un problema con la @ "(. *) Ha detto" versione alltogether: cosa succede se "Utente17 ha detto" l'ho già detto! "' - la regex troverà il torto "detto" –

+1

Non posso farlo, le linee hanno vari formati non per esempio X comando Y. – Svisstack

1

So Regex può fare un sacco di cose, ma qui è un punto di riferimento con Regex vs char.Split vs string.split

http://www.dotnetperls.com/split nella sezione benchmark

+1

Penso che quel sito abbia appena stuprato i miei occhi. – adelphus

+0

hai ragione su di esso -_- –

3

A parte precompilazione del regex, si potrebbe ottenere (probabilmente molto di più) benefici prestazionali scrivendo una regex più precisa. A questo proposito, .* è quasi sempre una cattiva scelta:

(.*) is connected significa: prima partita l'intera stringa (che è la parte .*), poi marcia indietro un carattere alla volta fino a quando è possibile abbinare is connected.

Ora, a meno che la stringa non sia molto corta o is connected appare molto vicino alla fine della stringa, questo è un sacco di backtracking che costa tempo.

Quindi, se è possibile perfezionare l'ammissione consentita, è possibile migliorare le prestazioni.

Ad esempio, se sono consentiti solo caratteri alfanumerici, allora (\w+) is connected sarà buono. Se si tratta di un qualsiasi tipo di caratteri non spazi bianchi, utilizzare (\S+) is connected. Ecc., In base alle regole per una corrispondenza valida.

Nel tuo esempio concreto, non sembra che tu stia facendo nulla con la corrispondenza catturata, quindi potresti anche eliminare completamente l'espressione regolare e cercare una sottostringa fissa. Il metodo che sarà il più veloce alla fine dipende molto dai tuoi input e requisiti effettivi.

+0

Gah! Stavo per scrivere un commento su uno dei grandi punti di forza delle espressioni regolari che potevano essere compilati per DFA, senza bisogno di backtracking. Ma poi ho esaminato i documenti per l'implementazione .NET di espressioni regolari e [* hai ragione! *] (Http://msdn.microsoft.com/en-us/library/dsy130b4.aspx) –

2

Non so se è possibile riutilizzare le espressioni o se il metodo è chiamato più volte, ma in tal caso è necessario precompilare le espressioni regolari. Prova questo:

private static readonly Regex xmlRegex = new Regex("YOUR EXPRESSION", RegexOptions.Compiled); 

Nel vostro campione, ogni volta che il metodo viene usato 'compila' l'espressione, ma questo è unneccesary come l'espressione è un const.Ora è precompilato questo compilato solo una volta. Lo svantaggio è che la prima volta che si accede all'espressione, è un po 'più lento.

+1

grazie ;-) questa è una buona risposta con questi campi statici – Svisstack

Problemi correlati