[c#] La mejor forma de reemplazar tokens en una plantilla de texto grande



4 Answers

La única situación en la que he tenido que hacer esto es enviar un correo electrónico con plantilla. En .NET esto es proporcionado por la clase MailDefinition . Entonces, así es como creas un mensaje de plantilla:

MailDefinition md = new MailDefinition();
md.BodyFileName = pathToTemplate;
md.From = "test@somedomain.com";

ListDictionary replacements = new ListDictionary();
replacements.Add("<%To%>", someValue);
// continue adding replacements

MailMessage msg = md.CreateMailMessage("test@someotherdomain.com", replacements, this);

Después de esto, msg.Body se creará al sustituir los valores en la plantilla. Supongo que puedes echar un vistazo a MailDefinition.CreateMailMessage () con Reflector :). Perdón por estar un poco fuera de tema, pero si este es su escenario, creo que es la manera más fácil.

Question

Tengo una plantilla de texto grande que necesita secciones tokenizadas reemplazadas por otro texto. Los tokens se ven más o menos así: ## NOMBRE DE USUARIO ##. Mi primer instinto es simplemente utilizar String.Replace (), pero ¿hay una forma mejor y más eficiente o ya está Optimizado para esto?




FastReplacer implementa reemplazo de token en O (n * log (n) + m) tiempo y utiliza 3 veces la memoria de la cadena original.

FastReplacer es bueno para ejecutar muchas operaciones de reemplazo en una cadena grande cuando el rendimiento es importante.

La idea principal es evitar modificar texto existente o asignar memoria nueva cada vez que se reemplaza una cadena.

Diseñamos FastReplacer para ayudarnos en un proyecto en el que tuvimos que generar un texto grande con una gran cantidad de operaciones de agregar y reemplazar. La primera versión de la aplicación tardó 20 segundos en generar el texto usando StringBuilder. La segunda versión mejorada que utilizó la clase String tomó 10 segundos. Luego implementamos FastReplacer y la duración se redujo a 0.1 segundos.




Las expresiones regulares serían la solución más rápida para codificar, pero si tiene muchos tokens diferentes, se volverá más lento. Si el rendimiento no es un problema, utiliza esta opción.

Un mejor enfoque sería definir token, como su "##" que puede escanear en el texto. Luego, seleccione qué reemplazar de una tabla hash con el texto que sigue al token como la clave.

Si esto es parte de un script de construcción, entonces nAnt tiene una gran característica para hacer esto llamado Filter Chains . El código para eso es de código abierto para que pueda ver cómo se hace para una implementación rápida.




string.Replace está bien. Preferiría usar un Regex, pero estoy loco por expresiones regulares.

Lo que hay que tener en cuenta es cuán grandes son estas plantillas. Si es realmente grande, y la memoria es un problema, es posible que desee crear un tokenizador personalizado que actúe en una secuencia. De esta forma, solo mantendrá una pequeña parte del archivo en la memoria mientras lo manipula.

Pero, para la implementación ingenua, string.Replace debería estar bien.




Si su plantilla es grande y tiene muchos tokens, probablemente no quiera caminar y reemplazar el token en la plantilla uno por uno, ya que eso daría como resultado una operación O (N * M) donde N es del tamaño de la plantilla. plantilla y M es el número de tokens para reemplazar.

El siguiente método acepta una plantilla y un diccionario de los pares de valores de claves que desea reemplazar. Al inicializar StringBuilder a un tamaño ligeramente mayor que el tamaño de la plantilla, debería dar como resultado una operación O (N) (es decir, no debería tener que crecer por sí mismo el registro N veces).

Finalmente, puede mover la construcción de los tokens a Singleton ya que solo necesita generarse una vez.

static string SimpleTemplate(string template, Dictionary<string, string> replacements)
{
   // parse the message into an array of tokens
   Regex regex = new Regex("(##[^#]+##)");
   string[] tokens = regex.Split(template);

   // the new message from the tokens
   var sb = new StringBuilder((int)((double)template.Length * 1.1));
   foreach (string token in tokens)
      sb.Append(replacements.ContainsKey(token) ? replacements[token] : token);

   return sb.ToString();
}





Related



Tags

c# c#   .net .net