2011-05-30 8 views
6

tengo que hacer algo como esto soñó .trReplace:Reemplazar una lista de carácter no válido con su versión válida (como tr)

str = str.trReplace("áéíüñ","aeiu&"); 

Debe cambiar esta cadena:

a stríng with inválid charactérs 

a:

a string with invalid characters 

Mis ideas actuales son:

str = str.Replace("á","a").Replace("é","e").Replace("í","ï"... 

y:

sb = new StringBuilder(str) 
sb.Replace("á","a"). 
sb.Replace("é","e") 
sb.Replace("í","ï"... 

Pero no creo que sean eficientes para las cadenas largas.

Respuesta

4

Richard tiene una buena respuesta, pero el rendimiento puede sufrir ligeramente en cadenas más largas (aproximadamente un 25% más lento que la sustitución de cadenas rectas como se muestra en la pregunta). Me sentí satisfecho de mirar esto un poco más allá. En realidad, hay varias buenas respuestas relacionadas ya en StackOverflow como se recoge a continuación:

Fastest way to remove chars from string

C# Stripping/converting one or more characters

También hay un buen artículo sobre la CodeProject que cubre las diferentes opciones.

http://www.codeproject.com/KB/string/fastestcscaseinsstringrep.aspx

Para explicar por qué la función proporcionada en respuesta Richards vuelve más lento con cadenas más largas se debe al hecho de que los reemplazos están sucediendo un carácter a la vez; por lo tanto, si tiene grandes secuencias de caracteres no mapeados, está desperdiciando ciclos adicionales mientras vuelve a anexar la cadena. Por lo tanto, si usted quiere tomar algunos puntos de la CodePlex artículo termina con una versión ligeramente modificada de respuesta Richards que se parece a:

private static readonly Char[] ReplacementChars = new[] { 'á', 'é', 'í', 'ü', 'ñ' }; 
private static readonly Dictionary<Char, Char> ReplacementMappings = new Dictionary<Char, Char> 
                   { 
                   { 'á', 'a'}, 
                   { 'é', 'e'}, 
                   { 'í', 'i'}, 
                   { 'ü', 'u'}, 
                   { 'ñ', '&'} 
                   }; 

private static string Translate(String source) 
{ 
    var startIndex = 0; 
    var currentIndex = 0; 
    var result = new StringBuilder(source.Length); 

    while ((currentIndex = source.IndexOfAny(ReplacementChars, startIndex)) != -1) 
    { 
    result.Append(source.Substring(startIndex, currentIndex - startIndex)); 
    result.Append(ReplacementMappings[source[currentIndex]]); 

    startIndex = currentIndex + 1; 
    } 

    if (startIndex == 0) 
    return source; 

    result.Append(source.Substring(startIndex)); 

    return result.ToString(); 
} 

NOTA No todos los casos extremos han sido probados.

NOTA Podría reemplazar ReplacementChars con ReplacementMappings.Keys.ToArray() por un pequeño costo.

Suponiendo que NO todos los caracteres son un sustituto, entonces esto realmente se ejecutará un poco más rápido que los reemplazos de cadenas straigt (nuevamente alrededor del 20%).

Dicho esto, recuerde cuando se considera el costo de rendimiento, de lo que realmente estamos hablando ... en este caso ... la diferencia entre la solución optimizada y la original es de 1 segundo más de 100.000 iteraciones en una cadena de 1.000 caracteres .

De cualquier manera, solo quería agregar algo de información a las respuestas a esta pregunta.

1

Lo que quiere es una forma de pasar por la cadena una vez y hacer todos los reemplazos. No estoy seguro de que la expresión regular sea la mejor forma de hacerlo si desea eficiencia. Podría ser que un cambio de mayúsculas y minúsculas (para todos los caracteres que desee reemplazar) en un ciclo for para probar cada carácter sea más rápido. Yo perfilaría los dos enfoques.

2

Hice algo similar para los pasaportes de la OACI. Los nombres tenían que ser 'transcritos'. Básicamente, tenía un diccionario de mapeos de char a char.

Dictionary<char, char> mappings; 

static public string Translate(string s) 
{ 
    var t = new StringBuilder(s.Length); 
    foreach (char c in s) 
    { 
     char to; 
     if (mappings.TryGetValue(c, out to)) 
     t.Append(to); 
     else 
     t.Append(c); 
    } 
    return t.ToString(); 
} 
+0

Gracias, me parece eficiente. Comenzaré a codificar esto (lo votaré tan pronto como tenga suficiente reputación :-) – MiguelM

+0

@ Richard - Realicé una corrección de error menor. Ya que tenía la configuración del código para comparar su enfoque con el enfoque de la pregunta, esto en realidad se ejecuta al mismo tiempo que el reemplazo en cadenas cortas, y en realidad es más lento en cadenas más largas. ¿Pensamientos? –

Cuestiones relacionadas