Почему вы считаете, что ваш метод неэффективен? На самом деле это один из самых эффективных способов сделать это.
Вы, конечно, должны прочитать символ в локальной переменной или использовать перечислитель, чтобы уменьшить количество обращений к массиву:
public static string RemoveSpecialCharacters(this string str) {
StringBuilder sb = new StringBuilder();
foreach (char c in str) {
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '.' || c == '_') {
sb.Append(c);
}
}
return sb.ToString();
}
Одна вещь, которая делает такой метод эффективным, заключается в том, что он хорошо масштабируется. Время выполнения будет зависеть от длины строки. Нет неприятных сюрпризов, если бы вы использовали его на большой струне.
Edit:
Я сделал быстрый тест производительности, выполняя каждую функцию по миллиону строк из 24 символов. Вот результаты:
Исходная функция: 54,5 мс.
Мое предлагаемое изменение: 47.1 мс.
Мой с настройкой емкости StringBuilder: 43,3 мс.
Регулярное выражение: 294,4 мс.
Редактировать 2:
Я добавил различие между A-Z и a-z в приведенном выше коде. (Я перезапускаю тест производительности, и нет заметной разницы.)
Редактировать 3:
Я протестировал решение lookup + char [], и оно работает примерно за 13 мс.
Цена, которую нужно заплатить, - это, конечно, инициализация огромной таблицы поиска и ее сохранение в памяти. Ну, это не так много данных, но много для такой тривиальной функции ...
private static bool[] _lookup;
static Program() {
_lookup = new bool[65536];
for (char c = '0'; c <= '9'; c++) _lookup[c] = true;
for (char c = 'A'; c <= 'Z'; c++) _lookup[c] = true;
for (char c = 'a'; c <= 'z'; c++) _lookup[c] = true;
_lookup['.'] = true;
_lookup['_'] = true;
}
public static string RemoveSpecialCharacters(string str) {
char[] buffer = new char[str.Length];
int index = 0;
foreach (char c in str) {
if (_lookup[c]) {
buffer[index] = c;
index++;
}
}
return new string(buffer, 0, index);
}