Avatar ·

Как удалить все символы из строки, кроме букв, цифр и дефиса, в C#?

Всем привет! Я новичок в C# и столкнулся с такой задачей: нужно очистить строку от всех символов, кроме букв (латиница и кириллица), цифр и дефиса (-). Например, есть строка: ```csharp string input = "Hello-World! How are you? (test) 123-456 #2024"; ``` Из неё должно получиться: ``` Hello-World How are you test 123-456 2024 ``` То есть, удаляются знаки препинания, пробелы, скобки, решётки и всё остальное, кроме букв, цифр и дефиса. Я пробовал использовать `Regex.Replace` с шаблоном `[^a-zA-Z0-9-]`, но он удаляет кириллицу, а мне нужно её сохранить. Если добавить `а-яА-Я`, то всё равно остаются какие-то проблемы с пробелами — они тоже удаляются, а мне нужно, чтобы пробелы оставались. Подскажите, как правильно составить регулярное выражение или есть другой способ? Желательно с примером кода. Заранее спасибо! Теги: C#, строки, регулярные выражения, очистка строк <<>>

Решение с помощью регулярного выражения

Ваша задача решается очень просто с помощью класса Regex из пространства имён System.Text.RegularExpressions. Главная проблема в вашем шаблоне — вы не учли пробелы и кириллицу. Вот правильный паттерн:

using System;
using System.Text.RegularExpressions;

string input = "Hello-World! How are you? (test) 123-456 #2024 Привет-Мир!";
string result = Regex.Replace(input, @"[^a-zA-Zа-яА-Я0-9\s-]", "");
Console.WriteLine(result);
// Вывод: Hello-World How are you test 123-456 2024 Привет-Мир

Объяснение шаблона

Разберём регулярное выражение [^a-zA-Zа-яА-Я0-9\s-]:

  • [^...] — символ отрицания. Означает "любой символ, кроме перечисленных".
  • a-zA-Z — все латинские буквы (строчные и заглавные).
  • а-яА-Я — все русские буквы (строчные и заглавные). Важно: используйте именно русские 'а' и 'я', а не английские.
  • 0-9 — все цифры.
  • \s — любой пробельный символ (пробел, табуляция, перевод строки).
  • - — сам дефис. Его нужно ставить в конце или начале диапазона, чтобы он не воспринимался как указатель диапазона.

Таким образом, Regex.Replace заменяет все символы, НЕ входящие в указанный набор, на пустую строку (удаляет их).

Альтернатива без регулярных выражений (для производительности)

Если вы обрабатываете очень много строк и производительность критична, можно использовать цикл с StringBuilder:

using System;
using System.Text;

string input = "Hello-World! How are you? (test) 123-456 #2024";
var sb = new StringBuilder(input.Length);

foreach (char c in input)
{
    if (char.IsLetterOrDigit(c) || c == '-' || char.IsWhiteSpace(c))
    {
        sb.Append(c);
    }
}

string result = sb.ToString();
Console.WriteLine(result);
// Вывод: Hello-World How are you test 123-456 2024

Этот метод работает быстрее на больших объёмах данных, но требует больше кода. Метод char.IsLetterOrDigit автоматически распознаёт буквы всех алфавитов, включая кириллицу.

Важные замечания

  • Если нужно сохранить только один пробел между словами (убрать лишние), добавьте после очистки: result = Regex.Replace(result.Trim(), @"\s+", " ");
  • Если дефис должен быть только внутри слов (не в начале или конце), обработайте отдельно: result = result.Trim('-');
  • Для .NET Core 3.0+ можно использовать Regex.Replace(input, @"[^\w\s-]", ""), где \w включает буквы, цифры и подчёркивание. Но \w не включает кириллицу в старых версиях .NET, так что будьте осторожны.

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

<<>>

Использование LINQ для элегантного решения

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

using System;
using System.Linq;

string input = "Hello-World! How are you? (test) 123-456 #2024";
string result = new string(input.Where(c => 
    char.IsLetterOrDigit(c) || c == '-' || char.IsWhiteSpace(c)).ToArray());
Console.WriteLine(result);
// Вывод: Hello-World How are you test 123-456 2024

Метод Where фильтрует символы по условию, а ToArray() преобразует результат в массив для конструктора строки. Это чистое, декларативное решение без побочных эффектов.

Дополнительный совет: обработка дефисов

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

string clean = new string(input.Where(c => 
    char.IsLetterOrDigit(c) || c == '-' || char.IsWhiteSpace(c)).ToArray());

// Удаляем лишние пробелы и дефисы по краям
clean = string.Join(" ", clean.Split(new[] { ' ' }, 
    StringSplitOptions.RemoveEmptyEntries));
clean = clean.Trim('-');

Console.WriteLine(clean);

Помните: LINQ-решения могут быть чуть медленнее StringBuilder на очень больших строках (более 100 000 символов), но для типичных задач их производительности более чем достаточно.