Как сделать метод Contains(string) регистронезависимым в C#?
Использование перегрузки Contains с StringComparison
Начиная с .NET Framework 4.0 и .NET Core 2.0, у строк появилась перегрузка метода Contains, которая принимает параметр StringComparison. Это самый правильный и производительный способ сделать поиск регистронезависимым. Вот как это работает:
string text = "Привет, Мир!";
bool result = text.Contains("мир", StringComparison.OrdinalIgnoreCase);
Console.WriteLine(result); // Выведет: True
Почему это лучше, чем ToLower()?
- Производительность:
ToLower()создаёт новую строку в памяти, что при больших объёмах данных может быть накладно.StringComparison.OrdinalIgnoreCaseработает напрямую с исходной строкой без выделения дополнительной памяти. - Корректность с учётом культуры:
ToLower()может давать неожиданные результаты для некоторых языков. Например, в турецком языке буква "I" в нижнем регистре — это "ı", а не "i".OrdinalIgnoreCaseиспользует инвариантную культуру и работает предсказуемо. - Читаемость: Код становится более явным и понятным — сразу видно, что поиск регистронезависимый.
Другие варианты StringComparison
В зависимости от задачи можно использовать разные значения:
StringComparison.OrdinalIgnoreCase— рекомендуется для большинства случаев, особенно для технических данных (имена файлов, идентификаторы, ключи). Основан на порядковых правилах сравнения без учёта культуры.StringComparison.InvariantCultureIgnoreCase— использует инвариантную культуру. Подходит, когда нужно сравнивать строки, которые должны вести себя одинаково во всех культурах (например, для отображения пользователю).StringComparison.CurrentCultureIgnoreCase— использует текущую культуру пользователя. Применяется, когда сравнение зависит от региональных правил (например, сортировка слов на датском языке).
Пример для списка строк
Часто требуется проверить, содержит ли элемент списка подстроку без учёта регистра:
List<string> items = new List<string>
{
"C# Программирование",
"Python разработка",
"Java для начинающих"
};
string searchTerm = "программирование";
var foundItems = items.Where(item =>
item.Contains(searchTerm, StringComparison.OrdinalIgnoreCase));
foreach (var item in foundItems)
Console.WriteLine(item); // Выведет: C# Программирование
Важное замечание
Если вы используете старую версию .NET Framework (до 4.0), то перегрузка с StringComparison недоступна. В таком случае можно написать свой метод-расширение:
public static class StringExtensions
{
public static bool ContainsIgnoreCase(this string source, string value)
{
return source.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;
}
}
// Использование:
bool result = text.ContainsIgnoreCase("мир");
Метод IndexOf с StringComparison доступен во всех версиях .NET, поэтому это хорошая альтернатива для обратной совместимости.
Вывод
Всегда используйте StringComparison.OrdinalIgnoreCase для регистронезависимого поиска. Это быстро, безопасно и является современным стандартом в C#. Избегайте ToLower()/ToUpper() — это устаревший подход, который может привести к багам и проблемам с производительностью.
Альтернативный подход: использование Regex с опцией IgnoreCase
Если вам нужен более гибкий поиск (например, с поддержкой шаблонов), можно использовать регулярные выражения:
using System.Text.RegularExpressions;
string text = "Привет, Мир!";
bool result = Regex.IsMatch(text, Regex.Escape("мир"), RegexOptions.IgnoreCase);
Console.WriteLine(result); // True
Плюсы:
- Можно комбинировать с другими опциями:
RegexOptions.IgnoreCase | RegexOptions.Multiline - Поддерживает сложные шаблоны поиска
Минусы:
- Медленнее, чем
ContainsсStringComparison(особенно при массовых вызовах) - Требуется экранирование спецсимволов через
Regex.Escape() - Избыточен для простого поиска подстроки
Этот подход стоит использовать только если вам действительно нужны возможности регулярных выражений (например, поиск с подстановочными знаками). Для обычного регистронезависимого поиска предпочтительнее первый вариант с StringComparison.OrdinalIgnoreCase.
Ответов пока нет.
Войдите чтобы оставить ответ