net how c# regex stringbuilder

c# - how - stringbuilder net



Reemplazos de Regex dentro de un StringBuilder (4)

Aquí hay un método de extensión que podrías usar para lograr lo que quieres. Toma un Dictionary donde la clave es el patrón que está buscando y el valor es con lo que desea reemplazarlo. Aún crea copias de la cadena entrante pero solo tiene que lidiar con esto una vez en lugar de crear copias para múltiples llamadas a Regex.Replace .

public static StringBuilder BulkReplace(this StringBuilder source, IDictionary<string, string> replacementMap) { if (source.Length == 0 || replacementMap.Count == 0) { return source; } string replaced = Regex.Replace(source.ToString(), String.Join("|", replacementMap.Keys.Select(Regex.Escape).ToArray()), m => replacementMap[m.Value], RegexOptions.IgnoreCase); return source.Clear().Append(replaced); }

Estoy escribiendo el contenido de un archivo de texto en un StringBuilder y luego deseo realizar una serie de acciones de búsqueda / reemplazo en el texto contenido en el StringBuilder usando expresiones regulares.

Me he encontrado con un problema ya que la función de reemplazo de StringBuilder no es capaz de aceptar argumentos de expresiones regulares.

Podría usar Regex.Replace en una cadena normal, pero tengo la impresión de que esto es ineficaz debido al hecho de que será necesario crear dos copias de la cadena en la memoria, ya que las cadenas .net son inmutables.

Una vez que haya actualizado el texto, pienso volver a escribirlo en el archivo original.

¿Cuál es la mejor y más eficiente manera de resolver mi problema?

EDITAR

Además de la (s) respuesta (s) a continuación, he encontrado las siguientes preguntas que también arrojan algo de luz sobre mi problema:


No estoy seguro de si esto ayuda a su situación o no, pero me topé con algunos topes de consumo de memoria con Regex y necesitaba un método de extensión de reemplazo de comodín simple en un StringBuilder para superarlo. Si necesita una combinación compleja de Regex y / o referencias inversas, esto no funcionará, pero si es simple * o? los reemplazos de comodines (con texto literal "reemplazar") harían el trabajo por usted, luego la solución al final de mi pregunta aquí debería al menos darle un impulso:

¿Alguien ha implementado un analizador Regex y / o Xml alrededor de StringBuilders o Streams?


Tienes 3 opciones:

  1. Haga esto de manera ineficiente con las cadenas como otros lo han recomendado aquí.

  2. Use la llamada .Matches() en su objeto Regex , y emule la forma en que funciona .Replace() (vea el # 3).

  3. Adapte la implementación de Regex de Regex para construir un Regex que acepte StringBuilder (¡y, por favor, compártalo aquí!) Casi todo el trabajo ya está hecho para usted en Mono, pero tomará tiempo repasar las partes que lo hacen funcionar en su Biblioteca propia. Regex de Mono aprovecha la implementación de Regex de Novell en 2002 de Regex , por extraño que parezca.

En Mono:

System.Text.RegularExpressions.Regex utiliza un RxCompiler para crear una instancia de IMachineFactory en forma de RxInterpreterFactory , que no sorprende que IMachine s sea RxInterpreter s. Hacer que esos emitan es la mayor parte de lo que necesita hacer, aunque si solo está buscando aprender cómo está estructurado para la eficiencia, es notable que gran parte de lo que está buscando está en su clase base, BaseMachine .

En particular, en BaseMachine están las cosas basadas en StringBuilder . En el método LTRReplace , primero LTRReplace una instancia de StringBuilder con la cadena inicial, y todo a partir de ahí se basa exclusivamente en StringBuilder. En realidad, es muy molesto que Regex no tenga métodos de StringBuilder para salir, si asumimos que la implementación interna de Microsoft .Net es similar.

Volviendo a la sugerencia 2, puede imitar el comportamiento de .Matches() llamando a .Matches() , rastreando dónde se encuentra en la cadena original y haciendo un bucle:

var matches = regex.Matches(original); var sb = new StringBuilder(original.Length); int pos = 0; // position in original string foreach(var match in matches) { sb.Append(original.Substring(pos, match.Index)); // Append the portion of the original we skipped pos = match.Index; // Make any operations you like on the match result, like your own custom Replace, or even run another Regex pos += match.Value.Length; } sb.Append(original.Substring(pos, original.Length - 1));

Pero, esto solo le ahorra algunas cadenas: el enfoque mod-Mono es el único que realmente lo hace bien.


La mejor y más eficiente solución para su tiempo es probar el enfoque más simple primero: olvide el StringBuilder y solo use Regex.Replace . Luego, averigüe qué tan lento es, puede que sea lo suficientemente bueno. No te olvides de probar la expresión regular en modo compilado y no compilado.

Si eso no es lo suficientemente rápido, considere usar un StringBuilder para cualquier reemplazo que pueda expresar de manera simple, y luego use Regex.Replace para el resto. Es posible que también desee considerar tratar de combinar reemplazos, reduciendo el número de expresiones regulares (y, por lo tanto, las cadenas intermedias) utilizadas.