Подтвердить что ты не робот

С#: удаление общих недопустимых символов из строки: улучшите этот алгоритм

Учитывайте требование убрать недопустимые символы из строки. Символы просто нужно удалить и заменить пустым или string.Empty.

char[] BAD_CHARS = new char[] { '!', '@', '#', '$', '%', '_' }; //simple example

foreach (char bad in BAD_CHARS)
{
    if (someString.Contains(bad))
      someString = someString.Replace(bad.ToString(), string.Empty);
}

Мне бы понравилось :

if (BAD_CHARS.Any(bc => someString.Contains(bc)))
    someString.Replace(bc,string.Empty); // bc is out of scope

Вопрос: Есть ли у вас какие-либо предложения по реорганизации этого алгоритма или какие-либо более простые, легко читаемые, эффективные, поддерживаемые алгоритмы?

4b9b3361

Ответ 1

char[] BAD_CHARS = new char[] { '!', '@', '#', '$', '%', '_' }; //simple example
someString = string.Concat(someString.Split(BAD_CHARS,StringSplitOptions.RemoveEmptyEntries));

должен сделать трюк (извините за любые небольшие ошибки синтаксиса, которые я нахожу на своем телефоне)

Ответ 2

Я не знаю о его удобочитаемости, но регулярное выражение может делать то, что вам нужно:

someString = Regex.Replace(someString, @"[[email protected]#$%_]", "");

Ответ 3

Класс string является неизменным (хотя тип ссылки), поэтому все его статические методы предназначены для возврата новой переменной string. Вызов someString.Replace без привязки к чему-либо не будет иметь никакого эффекта в вашей программе. - Похоже, вы исправили эту проблему.

Основная проблема с вашим предлагаемым алгоритмом заключается в том, что он многократно назначает множество новых переменных string, что потенциально может привести к большому результату. LINQ на самом деле ничего не помогает. (Я не делаю код значительно короче и, конечно, не читаем, на мой взгляд.)

Попробуйте использовать следующий метод расширения. Ключом является использование StringBuilder, что означает, что для выполнения во время выполнения назначается только один блок памяти.

private static readonly HashSet<char> badChars = 
    new HashSet<char> { '!', '@', '#', '$', '%', '_' };

public static string CleanString(this string str)
{
    var result = new StringBuilder(str.Length);
    for (int i = 0; i < str.Length; i++)
    {
        if (!badChars.Contains(str[i]))
            result.Append(str[i]);
    }
    return result.ToString();
}

Этот алгоритм также использует класс .NET 3.5 'HashSet', чтобы дать O(1) время поиска для обнаружения плохого char. Это делает общий алгоритм O(n), а не O(nm) вашего опубликованного (m - количество плохих символов); это также намного лучше с использованием памяти, как описано выше.

Ответ 4

Это быстрее, чем HashSet<T>. Кроме того, если вам нужно часто выполнять это действие, пожалуйста, рассмотрите основы этого вопроса, который я задал здесь.

private static readonly bool[] BadCharValues;

static StaticConstructor()
{
    BadCharValues = new bool[char.MaxValue+1];
    char[] badChars = { '!', '@', '#', '$', '%', '_' };
    foreach (char c in badChars)
        BadCharValues[c] = true;
}

public static string CleanString(string str)
{
    var result = new StringBuilder(str.Length);
    for (int i = 0; i < str.Length; i++)
    {
        if (!BadCharValues[str[i]])
            result.Append(str[i]);
    }
    return result.ToString();
}

Ответ 5

Зачем вам ДЕЙСТВИТЕЛЬНО понравилось? Код абсолютно не проще, вы просто заставляете метод расширения запроса в свой код.

В стороне, проверка Contains кажется избыточной, как концептуально, так и с точки зрения производительности. Contains должен все равно пробегать всю строку, вы можете просто вызвать Replace(bad.ToString(), string.Empty) для каждого символа и забыть о том, действительно ли он присутствует.

Конечно, регулярное выражение всегда является опцией и может быть более результативным (если не менее ясным) в такой ситуации.

Ответ 6

Что-то для рассмотрения - если это для паролей (скажем), вы хотите отсканировать и сохранить хорошие персонажи и предположить, что все остальное плохо. Его легче правильно фильтровать или хорошие вещи, а затем попытаться угадать все плохие вещи.

Для каждого персонажа  Если символ хорош → Держите его (скопируйте в буфер, что угодно.)

Джеф

Ответ 7

если вы все еще хотите сделать это по методу LINQy:

public static string CleanUp(this string orig)
{
    var badchars = new List<char>() { '!', '@', '#', '$', '%', '_' };

    return new string(orig.ToCharArray().Where(c => !badchars.Contains(c)).ToArray());
}

Ответ 8

Дополнительный совет. Если вы не хотите запоминать массив char, который недействителен для файлов, вы можете использовать Path.GetInvalidFileNameChars(). Если вы хотите его для Paths, он Path.GetInvalidPathChars

private static string RemoveInvalidChars(string str)
            {
                return string.Concat(str.Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries));
            }

Ответ 9

Это довольно чисто. Ограничивает его действительными символами вместо удаления недопустимых. Вы должны разделить его на константы, вероятно:

string clean = new string(@"Sour!ce Str&*(@ing".Where(c => 
@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.".Contains(c)).ToArray()