Очистка string от ненужнных char

Рейтинг: 2Ответов: 2Опубликовано: 05.05.2023

Подскажите хороший способ очистить string от ненужных char.

Найти эти ненужные символы и удалить из строки.

По сути мне нужны только a-z A-Z 0-9 и может быть ещё какие то символыю например дефис -.

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

Ещё, у той же структуры char есть различне методы Is и можно наверно их использовать.

Как лучше сделать и чтобы быстрее работало ?

Ответы

▲ 5Принят

Решение для .NET 7

static void Main(string[] args)
{
    string text = string.Concat(Enumerable.Repeat("HelloWorld", 10000000)); // 100M символов
    Console.WriteLine(text.Length);
    Stopwatch sw = Stopwatch.StartNew();
    Console.WriteLine(IsAsciiString(text));
    Console.WriteLine(sw.Elapsed);

    Console.ReadKey();
}

private static bool IsAsciiString(ReadOnlySpan<char> text)
{
    foreach (char c in text)
    {
        if (!char.IsAsciiLetterOrDigit(c))
            return false;
    }
    return true;
}

В отладке показывает

100000000
True
00:00:00.5075348

В релизе

100000000
True
00:00:00.1745654

А надо ли быстрее? 200 мегабайт данных за 0,1 секунды.

Теперь почистим строку

static void Main(string[] args)
{
    string text = string.Concat(Enumerable.Repeat("Hello World!", 10000000)); // 120M символов

    Stopwatch sw = Stopwatch.StartNew();
    Console.WriteLine(text.Length);
    string clean = CleanUpText(text);
    Console.WriteLine(clean.Length);
    Console.WriteLine(sw.Elapsed);

    Console.ReadKey();
}

private static string CleanUpText(ReadOnlySpan<char> text)
{
    var sb = new StringBuilder(text.Length < 32 ? text.Length : text.Length / 2);
    foreach (char c in text)
    {
        if (char.IsAsciiLetterOrDigit(c))
            sb.Append(c);
    }
    return sb.ToString();
}

В отладке

120000000
100000000
00:00:00.9601710

в релизе

120000000
100000000
00:00:00.3722909

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

▲ 4
        static void Main(string[] args){
            Regex rgx = new Regex(@"[^a-zA-Z0-9]");
            Console.WriteLine(rgx.IsMatch(args[0]));
            Console.WriteLine(rgx.Replace(args[0], ""));
        }

В конструктор регулярного выражения нужно включить все разрешённые символы (в данном случае a-z, A-Z и 0-9). IsMatch показывает, есть ли в строке нежелательные символы, а Replace удаляет их.

Так будет лучше. А нужно ли быстрее? Если это какое-то разовое действие, то быстрее не нужно, а если, скажем, требуется обрабатывать миллионы строк, то нужно отказаться от использования регулярных выражений в пользу работы с символами простыми циклами for (не foreach).