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

Если Вы хотите смочь искать целые строки и не просто символы:

src.Select((c, i) => src.Substring(i))
    .Count(sub => sub.StartsWith(target))

Read как "для каждого символа в строке, возьмите остальную часть строки, начинающей с того символа как подстрока; считайте его, если это запускается с целевой строки".

17
задан p.campbell 25 August 2009 в 18:14
поделиться

8 ответов

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

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

23
ответ дан 30 November 2019 в 09:57
поделиться

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

someString = Regex.Replace(someString, @"[!@#$%_]", "");
36
ответ дан 30 November 2019 в 09:57
поделиться

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

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();
}
7
ответ дан 30 November 2019 в 09:57
поделиться

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

Основная проблема предлагаемого вами алгоритма заключается в том, что он многократно присваивает множество новых строковых переменных, что потенциально может сильно снизить производительность. 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) время поиска для обнаружения неправильного символа. Это делает общий алгоритм O (n) , а не O (nm) вашего опубликованного алгоритма ( m - количество плохих символов); также намного лучше с использованием памяти, как объяснено выше.

18
ответ дан 30 November 2019 в 09:57
поделиться

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

Для каждого персонажа Если персонаж хорош -> Сохранить (скопировать в буфер, что угодно)

jeff

3
ответ дан 30 November 2019 в 09:57
поделиться

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

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

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

3
ответ дан 30 November 2019 в 09:57
поделиться

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

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

    return new string(orig.Where(c => !badchars.Contains(c)).ToArray());
}
4
ответ дан 30 November 2019 в 09:57
поделиться

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

string clean = new string(@"Sour!ce Str&*(@ing".Where(c => 
@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.".Contains(c)).ToArray()
2
ответ дан 30 November 2019 в 09:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: