2009-06-06 30 views
13

ho qualche stringa di modellomodo più veloce per sostituire stringa in un modello

questo è il mio {0} template {1} stringa

che ho intenzione di mettere i valori utente nell'utilizzo String.Format().

La stringa in realtà è così più a lungo per migliorare la leggibilità che uso:

questo è il mio {} goodName1 template {} goodName2 stringa

E poi String.Replace ogni parametro con il suo valore.

Come posso ottenere le massime prestazioni e leggibilità?

Forse non dovrei avere questo modello in un file (come ora) ma lo costruisco dinamicamente concatenando ad un generatore di stringhe e aggiungendo i param quando richiesto? Anche se è meno leggibile.

Quali sono le mie altre opzioni?

+1

E 'un peccato questa domanda si trasformò in un dibattito sulla velocità. La soluzione 'String.Replace' sostituita ha un problema peggiore. Se il testo di sostituzione contiene anche sottostringhe del modulo '{goodNameN}' allora saranno espanse o no? Si scopre che dipende dall'ordine in cui sono state fatte le sostituzioni. Questo è il tipo di sottile sfocatura che può essere innocuo per anni e poi mordere in modi misteriosi molto tempo dopo che il codice è stato dimenticato. –

risposta

14
+18

Deve essere in disaccordo - può essere importante. Solo * assicurati che * importi prima di ottimizzare, piuttosto che assumerlo. – Brian

+4

A volte importa davvero ... come in questo caso in cui Replace è stato sintonizzato da 20 secondi a 0.1 ... http://www.codeproject.com/Articles/298519/Fast-Token-Replacement-in-Csharp –

7

Come tutto, dipende. Se il codice verrà chiamato milioni di volte al giorno, allora pensa alle prestazioni. Se è un paio di volte al giorno, allora leggi.

Ho effettuato alcuni benchmark tra l'utilizzo di stringhe (immutabili) normali e StringBuilder. Fino a quando non inizierai a fare enormi quantità in poco tempo, non dovrai preoccuparti troppo.

+1

Sono d'accordo con Iain. Per maggiori informazioni consulta questo articolo su Code Project: http://www.codeproject.com/KB/string/string.aspx – Kane

7

La mia soluzione spontanea sarebbe simile a questa:

string data = "This is a {template1} that is {template2}."; 

Dictionary<string, string> replacements = new Dictionary<string, string>(){ 
    {"{template1}", "car"}, 
    {"{template2}", "red"}, 
}; 

foreach (string key in replacements.Keys) 
{ 
    data = data.Replace(key, replacements[key]); 
} 
Console.WriteLine(data); // outputs "This is a car that is red." 

Ho usato questo tipo di sostituzioni modello in diversi progetti reali e non hanno mai trovato ad essere un problema di prestazioni. Dal momento che è facile da usare e da capire, non ho visto alcun motivo per cambiarlo molto.

37

È possibile inserire i parametri in un dizionario e utilizzare il metodo Regex.Replace per sostituire tutti i parametri in una sostituzione. In questo modo il metodo si adatta bene se la stringa del modello diventa lunga o il numero di parametri aumenta.

Esempio:

Dictionary<string, string> parameters = new Dictionary<string, string>(); 
parameters.Add("goodName1", "asdf"); 
parameters.Add("goodName2", "qwerty"); 
string text = "this is my {goodName1} template {goodName2} string"; 
text = Regex.Replace(text, @"\{(.+?)\}", m => parameters[m.Groups[1].Value]); 
+0

Questa soluzione è la più performante, dovresti usare un metodo di estensione di qualche tipo per prendersi cura dei non -esistenti chiavi quando si cerca il dizionario però. –

+0

E \ {([^}] +) \} è più veloce rispetto all'utilizzo dell'operatore non-goloso. –

+0

@Guffa - Una buona nota da sottolineare è che 'm.Value' dovrebbe essere' m.Groups [1] .Value'. 'm.Value' restituisce lo stesso di' m.Groups [0] .Value', che corrisponde all'intera parte. – Zack

1

Il più veloce modo per farlo è con uno StringBuilder utilizzando singole chiamate a StringBuilder.Append(), in questo modo:

string result = new StringBuilder("this is my ") 
       .Append(UserVar1) 
       .Append(" template ") 
       .Append(UserVar2) 
       .Append(" string") 
       .ToString(); 

ho thoroughly benchmarked the framework code, e questo sarà essere il più veloce. Se si desidera migliorare la leggibilità, è possibile mantenere una stringa separata per mostrare all'utente e utilizzarla in background.

+2

Non è necessario farlo. Il compilatore C# lo compilerà esattamente come se fosse "stringa risultato =" questo è il mio modello "+ UserVar1 +" "+ UserVar2 +" stringa "' –

0

Se avete bisogno di una buona, veloce, ma semplice motore di template, si dovrebbe verificare StringTemplate. Per i modelli semplici che non richiedono alcun controllo logico o di flusso nel modello stesso, StringTemplate è GRANDE.

http://www.stringtemplate.org/download.html

3

Attenzione di impantanarsi con questo tipo di pensiero. A meno che questo codice non funzioni a centinaia di volte al minuto e il file del modello abbia diverse dimensioni di K, è più importante farlo. Non sprecare un minuto a pensare a problemi come questo. In generale, se si sta facendo molto con le manipolazioni di stringhe, utilizzare un generatore di stringhe. Ha persino un metodo di sostituzione. Ma, perché preoccuparsi. Al termine, e SE si riscontra un problema di prestazioni, utilizzare PerfMon e correggere i colli di bottiglia REALI in quel momento.

1

La stessa cosa sopra che Fredrick ha pubblicato sopra, ma con linq.

public static string FindandReplace(this string inputText, Dictionary<string, string> placeHolderValues) 
    { 
     if (!string.IsNullOrEmpty(inputText)) 
     { 
      return placeHolderValues.Keys.Aggregate(inputText, (current, key) => current.Replace(key, placeHolderValues[key])); 
     } 
     else return inputText; 
    } 
0

appena modificato la risposta di cui sopra al seguente: Metodo

string data = "This is a {template1} that is {template2}."; 

    Dictionary<string, string> replacements = new Dictionary<string, string>(){ 
     {"{template1}", "car"}, 
     {"{template2}", "red"}, 
    }; 

    data.Parse(replacements); 

Estensione:

public static class Parser 
{ 
    public static string Parse(this string template, Dictionary<string, string> replacements) 
    { 
     if (replacements.Count > 0) 
     { 
      template = replacements.Keys 
         .Aggregate(template, (current, key) => current.Replace(key, replacements[key])); 
     } 
     return template; 
    } 
} 

Spero che questo aiuti .. :)

Problemi correlati