Pourquoi le .Contains() classique vous décevra (et comment y remédier)
\n\nImaginez : vous écrivez une recherche dans un catalogue de livres en C#. L'utilisateur saisit « Tolstoi », alors que la base de données stocke « tolstoi » en minuscules. Le string.Contains("Tolstoi") classique renverra false. Une douleur familière ? Cette question a recueilli des milliers de vues sur Stack Overflow — et pour cause. En 2025, alors que .NET propose des outils puissants pour la manipulation des chaînes, utiliser l'ancienne approche revient à perdre des utilisateurs et des performances.
Dans cet article, nous allons analyser les 5 meilleures méthodes pour rendre .Contains() insensible à la casse en C#. Vous découvrirez quelle méthode choisir pour une vitesse maximale, et laquelle pour un fonctionnement correct avec différentes langues. C'est parti !
Le problème : pourquoi .Contains() est sensible à la casse par défaut ?
\n\nEn C#, la méthode string.Contains() utilise par défaut une comparaison Ordinal. Cela signifie que les caractères sont comparés octet par octet : 'A' (0x41) n'est pas égal à 'a' (0x61). Pour du contenu anglophone, c'est souvent acceptable, mais dans les applications multilingues (russe, allemand, turc), cette approche brise la logique de recherche.
Par exemple, en turc, la lettre 'i' en majuscule est 'İ', et non 'I'. Un simple ToLower() peut donner un résultat incorrect. Par conséquent, appeler text.ToLower().Contains(pattern.ToLower()) est une mauvaise pratique. Examinons les solutions modernes.
Méthode 1 : StringComparison.OrdinalIgnoreCase — votre nouveau standard
\n\nDepuis .NET 5 (et fonctionne parfaitement dans .NET 8/9), la méthode la plus rapide et la plus sûre consiste à utiliser la surcharge de Contains avec le paramètre StringComparison :
string text = "Guerre et Paix — Léon Tolstoï";\nstring searchTerm = "tolstoï";\n\nbool result = text.Contains(searchTerm, StringComparison.OrdinalIgnoreCase);\nConsole.WriteLine(result); // True\n\nPourquoi est-ce le meilleur choix ?
\n- \n
- Vitesse : OrdinalIgnoreCase fonctionne au niveau des octets, mais ignore la casse. C'est 2 à 3 fois plus rapide que CurrentCultureIgnoreCase. \n
- Prévisibilité : Ne dépend pas de la culture de l'utilisateur. "ß" (Eszett allemand) ne sera pas égal à "ss" si vous ne le souhaitez pas. \n
- Prise en charge : Disponible dans toutes les versions modernes de .NET (Core 2.1+). \n
Utilisez cette méthode lorsque vous avez besoin d'une simple comparaison insensible à la casse, et que vous ne travaillez pas avec des particularités linguistiques (tri, déclinaisons).
\n\nMéthode 2 : IndexOf() avec StringComparison — pour plus de contrôle
\n\nParfois, vous n'avez pas seulement besoin de vérifier la présence, mais aussi de connaître la position de l'occurrence. Ou vous travaillez avec des versions plus anciennes du .NET Framework, où Contains avec StringComparison n'existe pas. Dans ce cas, IndexOf() vient à la rescousse :
string text = "C# — le meilleur langage pour le backend";\nstring searchTerm = "meilleur";\n\nbool result = text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0;\nConsole.WriteLine(result); // True\n\n// Et si vous avez besoin d'obtenir la position :\nint index = text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase);\nConsole.WriteLine(index); // 4 (position à laquelle le mot commence)\n\nQuand l'utiliser :
\n- \n
- Dans les projets legacy (par exemple, .NET Framework 4.x). \n
- Lorsque vous devez trouver l'index de l'occurrence, et pas seulement vérifier sa présence. \n
- Pour des scénarios plus complexes (par exemple, recherche avec saut de caractères). \n
Important : IndexOf retourne -1 si la sous-chaîne n'est pas trouvée. Vérifiez toujours avec >= 0, et non > 0.
Méthode 3 : CultureInfo.CurrentCultureIgnoreCase — pour une recherche linguistiquement correcte
\n\nSi votre application doit prendre en compte