2011-03-05 5 views
24

Я пытаюсь получить несколько адресов электронной почты, разделенных «,» внутри строки из таблицы базы данных, но также возвращает мне пробелы, и я хочу быстро удалить пробелы.Самый быстрый способ удалить пробелы в строке

В следующем коде удаляются пробелы, но он также замедляется, когда я пытаюсь получить большое количество адресов электронной почты в строке, подобной 30000, а затем попытаюсь удалить пробел между ними. Чтобы удалить эти пробелы, требуется более четырех-пяти минут.

Regex Spaces = 
     new Regex(@"\s+", RegexOptions.Compiled); 
txtEmailID.Text = MultipleSpaces.Replace(emailaddress),""); 

Может кто-нибудь пожалуйста, скажите мне, как я могу удалить пробел в пределах второй даже для большого количества электронной почты?

+0

Пробел! = Пробелы (последний более широк и включает, например, разрывы строк). – delnan

+0

http://stackoverflow.com/q/1120198/102112 – Alex

+0

У меня возникли сомнения ... Вы удаляете пробелы из целой строки (т. Е. Те, которые содержат разделенные запятыми электронные письма), или из любого одного адреса одним один ? – digEmAll

ответ

44

Я хотел бы построить метод пользовательских расширений с помощью StringBuilder, как:

public static string ExceptChars(this string str, IEnumerable<char> toExclude) 
{ 
    StringBuilder sb = new StringBuilder(str.Length); 
    for (int i = 0; i < str.Length; i++) 
    { 
     char c = str[i]; 
     if (!toExclude.Contains(c)) 
      sb.Append(c); 
    } 
    return sb.ToString(); 
} 

Использование:

var str = s.ExceptChars(new[] { ' ', '\t', '\n', '\r' }); 

или даже быстрее:

var str = s.ExceptChars(new HashSet<char>(new[] { ' ', '\t', '\n', '\r' })); 

С версией HashSet, строка из 11 миллионов символов занимает менее 700 мс (и я в режиме отладки)

EDIT:

Предыдущий код является универсальным и позволяет исключить любой символ, но если вы хотите удалить только пробелы в самой быстрой, как вы можете использовать:

public static string ExceptBlanks(this string str) 
{ 
    StringBuilder sb = new StringBuilder(str.Length); 
    for (int i = 0; i < str.Length; i++) 
    { 
     char c = str[i]; 
     switch (c) 
     { 
      case '\r': 
      case '\n': 
      case '\t': 
      case ' ': 
       continue; 
      default: 
       sb.Append(c); 
       break; 
     } 
    } 
    return sb.ToString(); 
} 

EDIT 2 :

как правильно указано в комментариях, правильный способ удалить все пробелы используют char.IsWhiteSpace метод:

public static string ExceptBlanks(this string str) 
{ 
    StringBuilder sb = new StringBuilder(str.Length); 
    for (int i = 0; i < str.Length; i++) 
    { 
     char c = str[i]; 
     if(!char.IsWhiteSpace(c)) 
      sb.Append(c); 
    } 
    return sb.ToString(); 
} 
+2

вы можете создать хэш хэша для этого решения: 'byte [] hash = new byte [255];' если вы хотите исключить '\ t', вы делаете' b [(int) '\ t'] = 1', а затем проверьте то же самое. но он будет работать только для ascii :) – Andrey

+0

Да, это было бы очень быстро. В противном случае, если вы просто хотите удалить пробелы из строки, вы можете напрямую использовать переключатель в функции и пропустить IEnumerable.Contains :) – digEmAll

+0

Хммм ... приятное решение, лучше моего :) –

6

Вы должны попробовать String.Trim(). Он будет обрезать все пробелы от начала до конца строки

Или вы можете попробовать этот метод из связанного темы: [link]

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)); 
    } 
+1

Этот код выдает OOMemoryException с действительно длинными строками ... – digEmAll

+9

Ну, у вас должны быть очень серьезные причины для введения небезопасного кода в безопасный код. Чистящая строка определенно не та. – Andrey

+0

Я думаю, что 4-5 минут для выполнения простого действия - неприемлемо. Это может быть намного быстрее. –

5

С помощью LINQ вы можете сделать это просто:

emailaddress = new String(emailaddress 
            .Where(x=>x!=' ' && x!='\r' && x!='\n') 
            .ToArray()); 

I не сравнивал его с подходами stringbuilder, но намного быстрее, чем строковые подходы. Потому что он не создает много копий строк (строка неизменна и ее использование напрямую приводит к резкому падению памяти и скорости), поэтому она не будет использовать очень большую память и не будет замедлять скорость (за исключением одного дополнительного прохода через сначала строка).

+1

Я очень сомневаюсь, что это ** быстро ** – Andrey

+0

'Select' должен быть' Where' ... – digEmAll

+0

@Andrey: Он должен иметь линейное время работы и строить массив только один раз. Общие проблемы с регулярным выражением связаны с нелинейным временем выполнения, а проблемы с заменой обычных строк связаны с повторным копированием строки. Почему бы это решение не было быстрым, по сравнению с заменой Regex w/string? Единственное, о чем я могу думать, - это служебные вызовы функций. Без профилирования и то и другое, это спекуляция. –

14

Учитывая реализация string.Replace написана на C++ и часть CLR runtime я готов поспорить

email.Replace(" ","").Replace("\t","").Replace("\n","").Replace("\r","");

будет самой быстрой реализацией. Если вам нужно every type of whitespace, вы можете указать шестнадцатеричное значение эквивалента unicode.

+1

Да, это очень быстро, но это создает 4 строки вместо 1. Это немного замедляет работу в случае длинных строк, пользовательских реализация с использованием StringBuilder выполняется быстрее, чем это. – digEmAll

+0

@digEmAll Это адрес электронной почты, хотя и не очень интенсивный. Я бы согласился, если бы это был большой текстовый файл 1k –

+1

Насколько я понял, это единственная строка с большим количеством писем, разделенных запятыми ... но, честно говоря, я не уверен ... – digEmAll

1

Вы должны рассмотреть возможность замены пробелов в наборе записей в вашей хранимой процедуре или запросе с помощью функции REPLACE(), если возможно, & еще лучше исправить ваши записи БД, так как пространство в адресе электронной почты в любом случае недействительно.

Как уже упоминалось другими, вам необходимо продумать различные подходы. Если вы используете Regex вы должны сделать его минимально статическую переменную уровня класса:

public static Regex MultipleSpaces = new Regex(@"\s+", RegexOptions.Compiled); 

emailAddress.Where(x=>{ return x != ' ';}).ToString() может иметь функцию накладных расходов, хотя она может быть оптимизирована для инлайн от Microsoft - снова профилирование даст вам ответ.

Наиболее эффективным методом было бы распределить буфер и скопировать символ по символу в новый буфер и пропустить пробелы, как вы это делаете. C# поддерживает указатели, поэтому вы можете использовать небезопасный код, выделять необработанный буфер и использовать арифметику указателя для копирования, как в C, и это так быстро, как это возможно. REPLACE() в SQL будет обрабатывать его как это для вас.

2

Используйте метод TrimEnd() класса String.Вы можете найти отличный пример here.

+1

Trim * методы off Класс String только обрезает начало или конец – JohnZaj

4
emailaddress.Replace(" ", string.empty); 
1
string str = "Hi!! this is a bunch of text with spaces"; 

MessageBox.Show(new String(str.Where(c => c != ' ').ToArray())); 
2

Есть Много различных способов, некоторые быстрее, чем другие:

public static string StripTabsAndNewlines(this string str) { 

    //string builder (fast) 
    StringBuilder sb = new StringBuilder(str.Length); 
    for (int i = 0; i < str.Length; i++) { 
     if (! Char.IsWhiteSpace(s[i])) { 
      sb.Append(); 
     } 
    } 
    return sb.tostring(); 

    //linq (faster ?) 
    return new string(str.ToCharArray().Where(c => !Char.IsWhiteSpace(c)).ToArray()); 

    //regex (slow) 
    return Regex.Replace(str, @"\s+", "") 

} 
0
string input =Yourinputstring; 
string[] strings = input.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); 
foreach (string value in strings) 
{ 
    string newv= value.Trim(); 
    if (newv.Length > 0) 
    newline += value + "\r\n"; 
} 
0
string s = " Your Text "; 

string new = s.Replace(" ", string.empty); 

// Output: 
// "YourText" 
0

быстрый и общий способ сделать это (линия терминаторы, вкладки также будут обрабатываться). Regex мощные средства действительно не нужны для решения этой проблемы, но Regex может снизить производительность.

new string 
    (stringToRemoveWhiteSpaces 
     .Where 
     (
     c => !char.IsWhiteSpace(c) 
     ) 
     .ToArray<char>() 
    ) 
Смежные вопросы