2010-02-02 28 views
18

Tengo una cadena de la que tengo que eliminar el siguiente carácter: '\ r', '\ n' y '\ t'. He intentado tres formas diferentes de eliminar estos caracteres y los he comparado para que pueda obtener la solución más rápida.La forma más rápida de eliminar caracteres de la cadena

Los siguientes son los métodos y hay tiempo de ejecución cuando los encontré 1000000 veces:

Cabe solución más rápida si tengo 1 o 2 char a eliminar. Pero como ya he puesto en más carbón, comienza a tomar más tiempo

str = str.Replace("\r", string.Empty).Replace("\n", string.Empty).Replace("\t", string.Empty); 

Tiempo de ejecución = 1695

para 1 o 2 char, esto era más lento que String.Replace, pero para 3 charla mostró un mejor rendimiento.

string[] split = str.Split(new char[] { '\t', '\r', '\n' }, StringSplitOptions.None); 
str = split.Aggregate<string>((str1, str2) => str1 + str2); 

Tiempo de ejecución = 1030

el más lento de todos, incluso con 1 Char. Tal vez mi expresión regular no es la mejor.

str = Regex.Replace(str, "[\r\n\t]", string.Empty, RegexOptions.Compiled); 

Tiempo de ejecución = 3500

Estas son las tres soluciones que se me ocurrió. ¿Hay alguna solución mejor y más rápida que alguien aquí conozca, o cualquier mejora que pueda hacer en este código?

cadena que he utilizado para la evaluación comparativa:

StringBuilder builder = new StringBuilder(); 
     builder.AppendFormat("{0}\r\n{1}\t\t\t\r\n{2}\t\r\n{3}\r\n{4}\t\t\r\n{5}\r\n{6}\r\n{7}\r\n{8}\r\n{9}", 
     "SELECT ", 
     "[Extent1].[CustomerID] AS [CustomerID], ", 
     "[Extent1].[NameStyle] AS [NameStyle], ", 
     "[Extent1].[Title] AS [Title], ", 
      "[Extent1].[FirstName] AS [FirstName], ", 
      "[Extent1].[MiddleName] AS [MiddleName], ", 
      "[Extent1].[LastName] AS [LastName], ", 
      "[Extent1].[Suffix] AS [Suffix], ", 
      "[Extent1].[CompanyName] AS [CompanyName], ", 
      "[Extent1].[SalesPerson] AS [SalesPerson], "); 
     string str = builder.ToString(); 

Respuesta

16

Aquí está la versión insegura súper rápida, versión 2.

public static unsafe string StripTabsAndNewlines(string s) 
    { 
     int len = s.Length; 
     char* newChars = stackalloc char[len]; 
     char* currentChar = newChars; 

     for (int i = 0; i < len; ++i) 
     { 
      char c = s[i]; 
      switch (c) 
      { 
       case '\r': 
       case '\n': 
       case '\t': 
        continue; 
       default: 
        *currentChar++ = c; 
        break; 
      } 
     } 
     return new string(newChars, 0, (int)(currentChar - newChars)); 
    } 

Y aquí están los puntos de referencia (tiempo para despojar 1000000 cuerdas en ms)

 cornerback84's String.Replace:   9433 
    Andy West's String.Concat:    4756 
    AviJ's char array:      1374 
    Matt Howells' char pointers:   1163
+1

Sí lo es. Tiempo de ejecución = 195 – ata

+3

Por cierto, necesita una máquina nueva: P – ata

+1

Es un Xeon reciente: probablemente nuestros puntos de referencia estén configurados de manera diferente. –

2

bucle a través de la cadena y el uso (sólo uno) StringBuilder (con el argumento adecuado constructor, para evitar asignaciones de memoria innecesarias) para crear una nueva cadena podría se más rápido.

2
String.Join(null, str.Split(new char[] { '\t', '\r', '\n' }, 
    StringSplitOptions.None)); 

podría darle un aumento de rendimiento sobre el uso de Aggregate() desde Join() está diseñado para cuerdas.

EDITAR:

En realidad, esto podría ser aún mejor:

String.Concat(str.Split(new char[] { '\t', '\r', '\n' }, 
    StringSplitOptions.None)); 
+0

ejecució n tiempo = 754. Gracias – ata

+0

¡Agradable! Actualicé mi respuesta para usar Concat() en su lugar. Podría valer la pena intentarlo. –

+0

Hubo una ligera mejoría al usar String.Concat. Ahora, tiempo de ejecución = 734 – ata

8

creo que obtendrá el mejor rendimiento posible mediante la composición de la nueva cadena como una matriz de caracteres y sólo convertirlo a una cadena cuando haya terminado, así:

string s = "abc"; 
int len = s.Length; 
char[] s2 = new char[len]; 
int i2 = 0; 
for (int i = 0; i < len; i++) 
{ 
    char c = s[i]; 
    if (c != '\r' && c != '\n' && c != '\t') 
     s2[i2++] = c; 
} 
return new String(s2, 0, i2); 

EDIT: usando cuerdas (s2, 0, i2) en lugar de Trim(), por sugerencia

+0

Una corrección, debe devolver cadena nueva (s2) .TrimEnd ('\ 0'); Y el tiempo de ejecución = 309. Excelente – ata

+2

Infact Hice una pequeña modificación. Ya está manteniendo la longitud de la nueva matriz, es decir, i2. Entonces, en lugar de recortar, puede usar return new String (s2, 0, i2); Eso trae el tiempo de ejecución a 255 – ata

1

probar esto

string str = "something \tis \nbetter than nothing"; 
string removeChars = new String(new Char[]{'\n', '\t'}); 
string newStr = new string(str.ToCharArray().Where(c => !removeChars.Contains(c)).ToArray()); 
+3

Tiempo de ejecución = 27020. – ata

+1

¡LINQ es el trabajo del diablo! –

0
string str; 
str = str.Replace(Environment.NewLine, string.Empty).Replace("\t", string.Empty); 
+1

Esto no es diferente de la versión LENTA en la respuesta aceptada. El OP está pidiendo el más rápido. –

2

Aún más rápido:

public static string RemoveMultipleWhiteSpaces(string s) 
    { 
     char[] sResultChars = new char[s.Length]; 

     bool isWhiteSpace = false; 
     int sResultCharsIndex = 0; 

     for (int i = 0; i < s.Length; i++) 
     { 
      if (s[i] == ' ') 
      { 
       if (!isWhiteSpace) 
       { 
        sResultChars[sResultCharsIndex] = s[i]; 
        sResultCharsIndex++; 
        isWhiteSpace = true; 
       } 
      } 
      else 
      { 
       sResultChars[sResultCharsIndex] = s[i]; 
       sResultCharsIndex++; 
       isWhiteSpace = false; 
      } 
     } 

     return new string(sResultChars, 0, sResultCharsIndex); 
    } 
+0

¿Tiene algún punto de referencia? – Julian

Cuestiones relacionadas