Bonnes pratiques pour l’utilisation de chaînes dans .NETBest Practices for Using Strings in .NET

.NET offre une prise en charge complète du développement d’applications localisées et globalisées, et facilite l’application des conventions de la culture actuelle ou d’une culture spécifique lors de l’exécution d’opérations courantes telles que le tri et l’affichage de chaînes..NET provides extensive support for developing localized and globalized applications, and makes it easy to apply the conventions of either the current culture or a specific culture when performing common operations such as sorting and displaying strings. Toutefois, le tri ou la comparaison de chaînes n'est pas toujours une opération dépendante de la culture.But sorting or comparing strings is not always a culture-sensitive operation. Par exemple, les chaînes utilisées en interne par une application doivent généralement être gérées de la même manière dans toutes les cultures.For example, strings that are used internally by an application typically should be handled identically across all cultures. Quand des données de type chaîne culturellement indépendantes, telles que des balises XML, des balises HTML, des noms d'utilisateurs, des chemins d'accès aux fichiers et des noms d'objets système, sont interprétées comme si elles étaient dépendantes de la culture, le code d'application peut faire l'objet de bogues subtils, de performances médiocres et, dans certains cas, de problèmes de sécurité.When culturally independent string data, such as XML tags, HTML tags, user names, file paths, and the names of system objects, are interpreted as if they were culture-sensitive, application code can be subject to subtle bugs, poor performance, and, in some cases, security issues.

Cette rubrique examine les méthodes de tri, de comparaison et d’application de la casse pour les chaînes dans .NET, présente des recommandations pour sélectionner une méthode appropriée de gestion des chaînes et fournit des informations supplémentaires sur les méthodes de gestion des chaînes.This topic examines the string sorting, comparison, and casing methods in .NET, presents recommendations for selecting an appropriate string-handling method, and provides additional information about string-handling methods. Elle décrit également comment les données mises en forme, telles que les données numériques et les données de date et d'heure, sont traitées pour l'affichage et pour le stockage.It also examines how formatted data, such as numeric data and date and time data, is handled for display and for storage.

Recommandations relatives à l’utilisation de chaînesRecommendations for string usage

Dans le cadre du développement à l’aide de .NET, suivez les recommandations simples ci-après quand vous utilisez des chaînes :When you develop with .NET, follow these simple recommendations when you use strings:

Quand vous utilisez des chaînes, évitez les pratiques suivantes :Avoid the following practices when you use strings:

  • N'utilisez pas de surcharges qui ne spécifient pas explicitement ou implicitement les règles de comparaison de chaînes pour les opérations de chaînes.Do not use overloads that do not explicitly or implicitly specify the string comparison rules for string operations.
  • N'utilisez pas d'opérations de chaînes basées sur StringComparison.InvariantCulture dans la plupart des cas.Do not use string operations based on StringComparison.InvariantCulture in most cases. L'une des rares exceptions est quand vous rendez persistantes des données linguistiquement explicites, mais dont la culture n'est pas spécifiée.One of the few exceptions is when you are persisting linguistically meaningful but culturally agnostic data.
  • N'utilisez pas une surcharge de la méthode String.Compare ou CompareTo , et testez une valeur de retour de zéro pour déterminer si deux chaînes sont égales.Do not use an overload of the String.Compare or CompareTo method and test for a return value of zero to determine whether two strings are equal.
  • N'utilisez pas la mise en forme qui tient compte de la culture pour rendre des données numériques ou les données de date et d'heure sous forme de chaîne.Do not use culture-sensitive formatting to persist numeric data or date and time data in string form.

Spécification explicite de comparaisons de chaînesSpecifying string comparisons explicitly

La plupart des méthodes de manipulation de chaînes dans .NET sont surchargées.Most of the string manipulation methods in .NET are overloaded. Une ou plusieurs surcharges acceptent généralement des paramètres par défaut, contrairement à d'autres qui définissent avec précision la façon dont les chaînes doivent être comparées ou manipulées.Typically, one or more overloads accept default settings, whereas others accept no defaults and instead define the precise way in which strings are to be compared or manipulated. La plupart des méthodes qui ne s'appuient pas sur des valeurs par défaut incluent un paramètre de type StringComparison, qui est une énumération spécifiant explicitement des règles pour la comparaison de chaînes selon la culture et la casse.Most of the methods that do not rely on defaults include a parameter of type StringComparison, which is an enumeration that explicitly specifies rules for string comparison by culture and case. Le tableau suivant décrit les membres de l'énumération StringComparison .The following table describes the StringComparison enumeration members.

Membre StringComparisonStringComparison member DescriptionDescription
CurrentCulture Effectue une comparaison respectant la casse à l'aide de la culture actuelle.Performs a case-sensitive comparison using the current culture.
CurrentCultureIgnoreCase Effectue une comparaison ne respectant pas la casse à l'aide de la culture actuelle.Performs a case-insensitive comparison using the current culture.
InvariantCulture Effectue une comparaison respectant la casse à l'aide de la culture dite indifférente.Performs a case-sensitive comparison using the invariant culture.
InvariantCultureIgnoreCase Effectue une comparaison ne respectant pas la casse à l'aide de la culture dite indifférente.Performs a case-insensitive comparison using the invariant culture.
Ordinal Effectue une comparaison ordinale.Performs an ordinal comparison.
OrdinalIgnoreCase Effectue une comparaison ordinale ne respectant pas la casse.Performs a case-insensitive ordinal comparison.

Par exemple, la méthode IndexOf , qui retourne l'index d'une sous-chaîne contenue dans un objet String correspondant à un caractère ou à une chaîne, a neuf surcharges :For example, the IndexOf method, which returns the index of a substring in a String object that matches either a character or a string, has nine overloads:

Nous vous recommandons de sélectionner une surcharge qui n'utilise pas de valeurs par défaut, pour les raisons suivantes :We recommend that you select an overload that does not use default values, for the following reasons:

  • Certaines surcharges ayant des paramètres par défaut (celles qui recherchent un Char dans l'instance de chaîne) effectuent une comparaison ordinale, tandis que d'autres (celles qui recherchent une chaîne dans l'instance de chaîne) sont dépendantes de la culture.Some overloads with default parameters (those that search for a Char in the string instance) perform an ordinal comparison, whereas others (those that search for a string in the string instance) are culture-sensitive. Il est difficile de mémoriser quelle méthode utilise quelle valeur par défaut, et les surcharges peuvent être facilement confondues.It is difficult to remember which method uses which default value, and easy to confuse the overloads.

  • L'objectif du code qui s'appuie sur des valeurs par défaut pour les appels de méthode n'est pas clair.The intent of the code that relies on default values for method calls is not clear. Dans l'exemple suivant, qui s'appuie sur des valeurs par défaut, il est difficile de savoir si le développeur voulait en fait une comparaison ordinale ou linguistique de deux chaînes, ou si une différence de casse entre protocol et "http" pourrait entraîner le retour de false par le test d'égalité.In the following example, which relies on defaults, it is difficult to know whether the developer actually intended an ordinal or a linguistic comparison of two strings, or whether a case difference between protocol and "http" might cause the test for equality to return false.

    string protocol = GetProtocol(url);       
    if (String.Equals(protocol, "http")) {
       // ...Code to handle HTTP protocol.
    }
    else {
       throw new InvalidOperationException();
    }
    
    Dim protocol As String = GetProtocol(url)       
    If String.Equals(protocol, "http") Then
       ' ...Code to handle HTTP protocol.
    Else
       Throw New InvalidOperationException()
    End If   
    

En général, nous vous recommandons d'appeler une méthode qui ne s'appuie pas sur des valeurs par défaut, car elle rend l'objectif du code non équivoque.In general, we recommend that you call a method that does not rely on defaults, because it makes the intent of the code unambiguous. Cela rend ensuite le code plus lisible et plus facile à déboguer et à gérer.This, in turn, makes the code more readable and easier to debug and maintain. L'exemple suivant aborde les questions soulevées à propos de l'exemple précédent.The following example addresses the questions raised about the previous example. Il explique que la comparaison ordinale est utilisée et que les différences de casse sont ignorées.It makes it clear that ordinal comparison is used and that differences in case are ignored.

string protocol = GetProtocol(url);       
if (String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase)) {
   // ...Code to handle HTTP protocol.
}
else {
   throw new InvalidOperationException();
}
Dim protocol As String = GetProtocol(url)       
If String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase) Then
   ' ...Code to handle HTTP protocol.
Else
   Throw New InvalidOperationException()
End If   

Détails de la comparaison de chaînesThe details of string comparison

La comparaison de chaînes est le cœur de nombreuses opérations liées aux chaînes, en particulier le tri et le test d'égalité.String comparison is the heart of many string-related operations, particularly sorting and testing for equality. Les chaînes sont triées dans un ordre déterminé : si "my" s'affiche avant "string" dans une liste triée de chaînes, "my" doit être considéré comme inférieur ou égal à "string".Strings sort in a determined order: If "my" appears before "string" in a sorted list of strings, "my" must compare less than or equal to "string". En outre, la comparaison définit implicitement l'égalité.Additionally, comparison implicitly defines equality. L'opération de comparaison retourne zéro pour les chaînes qu'il estime égales.The comparison operation returns zero for strings it deems equal. Considérer qu'aucune chaîne n'est inférieure à l'autre constitue une bonne interprétation.A good interpretation is that neither string is less than the other. La plupart des opérations significatives impliquant des chaînes incluent l'une des procédures suivantes, ou les deux : comparaison avec une autre chaîne et exécution d'une opération de tri bien définie.Most meaningful operations involving strings include one or both of these procedures: comparing with another string, and executing a well-defined sort operation.

Notes

Vous pouvez télécharger les Sorting Weight Tables, un ensemble de fichiers texte qui contiennent des informations sur les poids des caractères utilisés dans les opérations de tri et de comparaison pour les systèmes d’exploitation Windows et la Default Unicode Collation Element Table, la version la plus récente de la table de pondération de tri pour Linux et macOS.You can download the Sorting Weight Tables, a set of text files that contain information on the character weights used in sorting and comparison operations for Windows operating systems, and the Default Unicode Collation Element Table, the latest version of the sort weight table for Linux and macOS. La version spécifique de la table de pondération de tri sur Linux et macOS varie selon la version des bibliothèques International Components for Unicode installées sur le système.The specific version of the sort weight table on Linux and macOS depends on the version of the International Components for Unicode libraries installed on the system. Pour plus d’informations sur les versions ICU et les versions Unicode qu’elles implémentent, consultez Téléchargement d’ICU.For information on ICU versions and the Unicode versions that they implement, see Downloading ICU.

Toutefois, l'évaluation de l'égalité ou de l'ordre de tri de deux chaînes ne produit pas un résultat correct unique ; le résultat dépend des critères utilisés pour comparer les chaînes.However, evaluating two strings for equality or sort order does not yield a single, correct result; the outcome depends on the criteria used to compare the strings. En particulier, les comparaisons de chaînes qui sont ordinales ou basées sur les conventions de casse et de tri de la culture actuelle ou la culture invariante (culture aux paramètres régionaux non spécifiés basée sur la langue anglaise) peuvent produire des résultats différents.In particular, string comparisons that are ordinal or that are based on the casing and sorting conventions of the current culture or the invariant culture (a locale-agnostic culture based on the English language) may produce different results.

En outre, les comparaisons de chaînes à l’aide de différentes versions de .NET ou à l’aide de .NET sur différents systèmes d’exploitation ou des versions différentes de système d’exploitation peuvent retourner des résultats différents.In addition, string comparisons using different versions of .NET or using .NET on different operating systems or operating system versions may return different results. Pour plus d’informations, consultez Chaînes et norme Unicode.For more information, see Strings and the Unicode Standard.

Comparaisons de chaînes qui utilisent la culture actuelleString comparisons that use the current culture

L'un des critères à prendre en compte est l'utilisation des conventions de la culture actuelle lors de la comparaison de chaînes.One criterion involves using the conventions of the current culture when comparing strings. Les comparaisons basées sur la culture actuelle utilisent la culture ou les paramètres régionaux actuels du thread.Comparisons that are based on the current culture use the thread's current culture or locale. Si la culture n'est pas définie par l'utilisateur, sa valeur par défaut est le paramètre défini dans la fenêtre Options régionales du Panneau de configuration.If the culture is not set by the user, it defaults to the setting in the Regional Options window in Control Panel. Vous devez toujours utiliser des comparaisons basées sur la culture actuelle quand les données sont linguistiquement pertinentes et quand elles reflètent l'intervention de l'utilisateur dépendante de la culture.You should always use comparisons that are based on the current culture when data is linguistically relevant, and when it reflects culture-sensitive user interaction.

Toutefois, le comportement de la comparaison et de la casse dans .NET change en fonction de la culture.However, comparison and casing behavior in .NET changes when the culture changes. Cela se produit quand une application s'exécute sur un ordinateur dont la culture est différente de celle de l'ordinateur sur lequel l'application a été développée, ou quand le thread en cours d'exécution change sa culture.This happens when an application executes on a computer that has a different culture than the computer on which the application was developed, or when the executing thread changes its culture. Ce comportement est intentionnel, mais il reste peu évident à de nombreux développeurs.This behavior is intentional, but it remains non-obvious to many developers. L'exemple suivant illustre les différences au niveau de l'ordre de tri entre les cultures Anglais (États-Unis) ("en-US") et Suédois ("sv-SE").The following example illustrates differences in sort order between the U.S. English ("en-US") and Swedish ("sv-SE") cultures. Notez que les mots « ångström », « Windows » et « Visual Studio » s’affichent à des positions différentes dans les tableaux de chaînes triées.Note that the words "ångström", "Windows", and "Visual Studio" appear in different positions in the sorted string arrays.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      string[] values= { "able", "ångström", "apple", "Æble", 
                         "Windows", "Visual Studio" };
      Array.Sort(values);
      DisplayArray(values);

      // Change culture to Swedish (Sweden).
      string originalCulture = CultureInfo.CurrentCulture.Name;
      Thread.CurrentThread.CurrentCulture = new CultureInfo("sv-SE");
      Array.Sort(values);
      DisplayArray(values);

      // Restore the original culture.
      Thread.CurrentThread.CurrentCulture = new CultureInfo(originalCulture);
    }
    
    private static void DisplayArray(string[] values)
    {
      Console.WriteLine("Sorting using the {0} culture:",  
                        CultureInfo.CurrentCulture.Name);
      foreach (string value in values)
         Console.WriteLine("   {0}", value);

      Console.WriteLine();
    }
}
// The example displays the following output:
//       Sorting using the en-US culture:
//          able
//          Æble
//          ångström
//          apple
//          Visual Studio
//          Windows
//       
//       Sorting using the sv-SE culture:
//          able
//          Æble
//          apple
//          Windows
//          Visual Studio
//          ångström
Imports System.Globalization
Imports System.Threading

Module Example
   Public Sub Main()
      Dim values() As String = { "able", "ångström", "apple", _
                                 "Æble", "Windows", "Visual Studio" }
      Array.Sort(values)
      DisplayArray(values)

      ' Change culture to Swedish (Sweden).
      Dim originalCulture As String = CultureInfo.CurrentCulture.Name
      Thread.CurrentThread.CurrentCulture = New CultureInfo("sv-SE")
      Array.Sort(values)
      DisplayArray(values)

      ' Restore the original culture.
      Thread.CurrentThread.CurrentCulture = New CultureInfo(originalCulture)
    End Sub
    
    Private Sub DisplayArray(values() As String)
      Console.WRiteLine("Sorting using the {0} culture:", _ 
                        CultureInfo.CurrentCulture.Name)
      For Each value As String In values
         Console.WriteLine("   {0}", value)
      Next
      Console.WriteLine()   
    End Sub
End Module
' The example displays the following output:
'       Sorting using the en-US culture:
'          able
'          Æble
'          ångström
'          apple
'          Visual Studio
'          Windows
'       
'       Sorting using the sv-SE culture:
'          able
'          Æble
'          apple
'          Windows
'          Visual Studio
'          ångström

Les comparaisons ne respectant pas la casse qui utilisent la culture actuelle sont identiques aux comparaisons dépendantes de la culture, mais elles ignorent la casse, comme défini par la culture actuelle du thread.Case-insensitive comparisons that use the current culture are the same as culture-sensitive comparisons, except that they ignore case as dictated by the thread's current culture. Ce comportement peut également se manifester dans les ordres de tri.This behavior may manifest itself in sort orders as well.

Les comparaisons qui utilisent la sémantique de la culture actuelle sont la valeur par défaut pour les méthodes suivantes :Comparisons that use current culture semantics are the default for the following methods:

Dans tous les cas, nous vous recommandons d'appeler une surcharge qui a un paramètre StringComparison , afin que l'objectif de l'appel de la méthode soit clair.In any case, we recommend that you call an overload that has a StringComparison parameter to make the intent of the method call clear.

Des bogues, plus ou moins subtils, peuvent émerger quand des données de type chaîne non linguistiques sont interprétées linguistiquement, ou quand des données de type chaîne d'une culture particulière sont interprétées à l'aide des conventions d'une autre culture.Subtle and not so subtle bugs can emerge when non-linguistic string data is interpreted linguistically, or when string data from a particular culture is interpreted using the conventions of another culture. L'exemple canonique est le problème du caractère I en turc.The canonical example is the Turkish-I problem.

Dans presque tous les alphabets latins, y compris l'anglais (États-Unis), le caractère "i" (\u0069) est la version en minuscule du caractère "I" (\u0049).For nearly all Latin alphabets, including U.S. English, the character "i" (\u0069) is the lowercase version of the character "I" (\u0049). Cette règle de casse devient rapidement la valeur par défaut pour quelqu'un qui effectue de la programmation dans une telle culture.This casing rule quickly becomes the default for someone programming in such a culture. Toutefois, l’alphabet turc ("tr-TR") inclut un caractère "I avec un point", "İ" (\u0130), qui est la version en majuscule de "i".However, the Turkish ("tr-TR") alphabet includes an "I with a dot" character "İ" (\u0130), which is the capital version of "i". Le turc comprend également un caractère "i sans point" minuscule, "ı" (\u0131), dont la majuscule est "I".Turkish also includes a lowercase "i without a dot" character, "ı" (\u0131), which capitalizes to "I". Ce comportement se produit également dans la culture azérie ("az").This behavior occurs in the Azerbaijani ("az") culture as well.

Par conséquent, les suppositions faites sur la mise en majuscule du "i" ou de la mise en minuscule du "I" ne sont pas valides dans toutes les cultures.Therefore, assumptions made about capitalizing "i" or lowercasing "I" are not valid among all cultures. Si vous utilisez les surcharges par défaut pour les routines de comparaison de chaînes, elles varieront suivant les cultures.If you use the default overloads for string comparison routines, they will be subject to variance between cultures. Si les données à comparer sont non linguistiques, l'utilisation de surcharges par défaut peut produire des résultats indésirables, comme le montre la tentative suivante d'exécution d'une comparaison ne respectant pas la casse des chaînes "file" et "FILE".If the data to be compared is non-linguistic, using the default overloads can produce undesirable results, as the following attempt to perform a case-insensitive comparison of the strings "file" and "FILE" illustrates.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      string fileUrl = "file";
      Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}", 
                       fileUrl.StartsWith("FILE", true, null));
      Console.WriteLine();
      
      Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}", 
                        fileUrl.StartsWith("FILE", true, null));
   }
}
// The example displays the following output:
//       Culture = English (United States)
//       (file == FILE) = True
//       
//       Culture = Turkish (Turkey)
//       (file == FILE) = False
Imports System.Globalization
Imports System.Threading

Module Example
   Public Sub Main()
      Dim fileUrl = "file"
      Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
      Console.WriteLine("Culture = {0}", _
                        Thread.CurrentThread.CurrentCulture.DisplayName)
      Console.WriteLine("(file == FILE) = {0}", _ 
                       fileUrl.StartsWith("FILE", True, Nothing))
      Console.WriteLine()
      
      Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")
      Console.WriteLine("Culture = {0}", _
                        Thread.CurrentThread.CurrentCulture.DisplayName)
      Console.WriteLine("(file == FILE) = {0}", _ 
                        fileUrl.StartsWith("FILE", True, Nothing))
   End Sub
End Module
' The example displays the following output:
'       Culture = English (United States)
'       (file == FILE) = True
'       
'       Culture = Turkish (Turkey)
'       (file == FILE) = False

Cette comparaison peut provoquer de sérieux problèmes si la culture est utilisée par inadvertance dans des paramètres de sécurité sensibles, comme dans l'exemple suivant.This comparison could cause significant problems if the culture is inadvertently used in security-sensitive settings, as in the following example. Un appel de méthode comme IsFileURI("file:") retourne true si la culture actuelle est Anglais (États-Unis), mais false si la culture actuelle est Turc.A method call such as IsFileURI("file:") returns true if the current culture is U.S. English, but false if the current culture is Turkish. Par conséquent, sur les systèmes turcs, quelqu'un pourrait contourner les mesures de sécurité qui bloquent l'accès aux URI ne respectant pas la casse qui commencent par "FILE:".Thus, on Turkish systems, someone could circumvent security measures that block access to case-insensitive URIs that begin with "FILE:".

public static bool IsFileURI(String path) 
{
   return path.StartsWith("FILE:", true, null);
}
Public Shared Function IsFileURI(path As String) As Boolean 
   Return path.StartsWith("FILE:", True, Nothing)
End Function

Dans ce cas, étant donné que « file : » est destiné à être interprété comme un identificateur non linguistique et indépendant de la culture, le code doit plutôt être écrit comme indiqué dans l’exemple suivant :In this case, because "file:" is meant to be interpreted as a non-linguistic, culture-insensitive identifier, the code should instead be written as shown in the following example:

public static bool IsFileURI(string path) 
{
   return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
}
Public Shared Function IsFileURI(path As String) As Boolean 
    Return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase)
End Function

Opérations de chaînes ordinalesOrdinal string operations

La spécification de la valeur StringComparison.Ordinal ou StringComparison.OrdinalIgnoreCase dans un appel de méthode correspond à une comparaison non linguistique dans laquelle les fonctionnalités de langages naturels sont ignorées.Specifying the StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase value in a method call signifies a non-linguistic comparison in which the features of natural languages are ignored. Les méthodes qui sont appelées avec ces valeurs StringComparison font reposer les décisions d'opération de chaîne sur de simples comparaisons d'octets plutôt que sur la casse ou des tables d'équivalences paramétrables par la culture.Methods that are invoked with these StringComparison values base string operation decisions on simple byte comparisons instead of casing or equivalence tables that are parameterized by culture. Dans la plupart des cas, cette approche correspond le mieux à l'interprétation de chaînes prévue tout en rendant le code plus rapide et plus fiable.In most cases, this approach best fits the intended interpretation of strings while making code faster and more reliable.

Les comparaisons ordinales sont des comparaisons de chaînes dans lesquelles chaque octet de chaque chaîne est comparé sans interprétation linguistique ; par exemple, "windows" ne correspond pas à "Windows".Ordinal comparisons are string comparisons in which each byte of each string is compared without linguistic interpretation; for example, "windows" does not match "Windows". Il s’agit fondamentalement d’un appel à la fonction strcmp du runtime C.This is essentially a call to the C runtime strcmp function. Utilisez cette comparaison quand le contexte indique que les chaînes doivent correspondre exactement ou demande une stratégie de correspondance classique.Use this comparison when the context dictates that strings should be matched exactly or demands conservative matching policy. En outre, la comparaison ordinale est l'opération de comparaison la plus rapide, car elle n'applique aucune règle linguistique lors de la détermination d'un résultat.Additionally, ordinal comparison is the fastest comparison operation because it applies no linguistic rules when determining a result.

Les chaînes dans .NET peuvent contenir des caractères Null incorporés.Strings in .NET can contain embedded null characters. L'une des différences les plus évidentes entre la comparaison ordinale et la comparaison dépendante de la culture (y compris les comparaisons qui utilisent la culture dite indifférente) concerne la gestion des caractères Null incorporés dans une chaîne.One of the clearest differences between ordinal and culture-sensitive comparison (including comparisons that use the invariant culture) concerns the handling of embedded null characters in a string. Ces caractères sont ignorés quand vous utilisez les méthodes String.Compare et String.Equals pour effectuer des comparaisons dépendantes de la culture (notamment des comparaisons qui utilisent la culture dite indifférente).These characters are ignored when you use the String.Compare and String.Equals methods to perform culture-sensitive comparisons (including comparisons that use the invariant culture). Par conséquent, dans les comparaisons dépendantes de la culture, les chaînes qui contiennent des caractères Null incorporés peuvent être considérées comme égales à des chaînes qui n'en contiennent pas.As a result, in culture-sensitive comparisons, strings that contain embedded null characters can be considered equal to strings that do not.

Important

Les méthodes de comparaison de chaînes ignorent les caractères Null incorporés, contrairement aux méthodes de recherche de chaînes telles que String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOfet String.StartsWith .Although string comparison methods disregard embedded null characters, string search methods such as String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOf, and String.StartsWith do not.

L’exemple suivant effectue une comparaison dépendante de la culture de la chaîne "AA" avec une chaîne semblable qui contient plusieurs caractères null incorporés entre "A" et "a", et montre comment les deux chaînes sont considérées comme égales :The following example performs a culture-sensitive comparison of the string "Aa" with a similar string that contains several embedded null characters between "A" and "a", and shows how the two strings are considered equal:

using System;

public class Example
{
   public static void Main()
   {
      string str1 = "Aa";
      string str2 = "A" + new String('\u0000', 3) + "a";
      Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", 
                        str1, ShowBytes(str1), str2, ShowBytes(str2));
      Console.WriteLine("   With String.Compare:");
      Console.WriteLine("      Current Culture: {0}", 
                        String.Compare(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}", 
                        String.Compare(str1, str2, StringComparison.InvariantCulture));

      Console.WriteLine("   With String.Equals:");
      Console.WriteLine("      Current Culture: {0}", 
                        String.Equals(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}", 
                        String.Equals(str1, str2, StringComparison.InvariantCulture));
   }
   
   private static string ShowBytes(string str)
   {
      string hexString = String.Empty;
      for (int ctr = 0; ctr < str.Length; ctr++)
      {
         string result = String.Empty;
         result = Convert.ToInt32(str[ctr]).ToString("X4");
         result = " " + result.Substring(0,2) + " " + result.Substring(2, 2);
         hexString += result;
      }
      return hexString.Trim();
   }
}
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Current Culture: 0
//          Invariant Culture: 0
//       With String.Equals:
//          Current Culture: True
//          Invariant Culture: True
Module Example
   Public Sub Main()
      Dim str1 As String = "Aa"
      Dim str2 As String = "A" + New String(Convert.ToChar(0), 3) + "a"
      Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
                        str1, ShowBytes(str1), str2, ShowBytes(str2))
      Console.WriteLine("   With String.Compare:")
      Console.WriteLine("      Current Culture: {0}", _
                        String.Compare(str1, str2, StringComparison.CurrentCulture))
      Console.WriteLine("      Invariant Culture: {0}", _
                        String.Compare(str1, str2, StringComparison.InvariantCulture))

      Console.WriteLine("   With String.Equals:")
      Console.WriteLine("      Current Culture: {0}", _
                        String.Equals(str1, str2, StringComparison.CurrentCulture))
      Console.WriteLine("      Invariant Culture: {0}", _
                        String.Equals(str1, str2, StringComparison.InvariantCulture))
   End Sub
   
   Private Function ShowBytes(str As String) As String
      Dim hexString As String = String.Empty
      For ctr As Integer = 0 To str.Length - 1
         Dim result As String = String.Empty
         result = Convert.ToInt32(str.Chars(ctr)).ToString("X4")
         result = " " + result.Substring(0,2) + " " + result.Substring(2, 2)
         hexString += result
      Next
      Return hexString.Trim()
   End Function
End Module

Toutefois, les chaînes ne sont pas considérées comme égales quand vous utilisez la comparaison ordinale, comme le montre l’exemple suivant :However, the strings are not considered equal when you use ordinal comparison, as the following example shows:

Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", 
                  str1, ShowBytes(str1), str2, ShowBytes(str2));
Console.WriteLine("   With String.Compare:");
Console.WriteLine("      Ordinal: {0}", 
                  String.Compare(str1, str2, StringComparison.Ordinal));

Console.WriteLine("   With String.Equals:");
Console.WriteLine("      Ordinal: {0}", 
                  String.Equals(str1, str2, StringComparison.Ordinal));
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Ordinal: 97
//       With String.Equals:
//          Ordinal: False
Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
                  str1, ShowBytes(str1), str2, ShowBytes(str2))
Console.WriteLine("   With String.Compare:")
Console.WriteLine("      Ordinal: {0}", _
                  String.Compare(str1, str2, StringComparison.Ordinal))

Console.WriteLine("   With String.Equals:")
Console.WriteLine("      Ordinal: {0}", _
                  String.Equals(str1, str2, StringComparison.Ordinal))
' The example displays the following output:
'    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
'       With String.Compare:
'          Ordinal: 97
'       With String.Equals:
'          Ordinal: False

Les comparaisons ordinales ne respectant pas la casse sont l'approche la plus conservatrice suivante.Case-insensitive ordinal comparisons are the next most conservative approach. Ces comparaisons ignorent la plus grande partie de la casse ; par exemple, "windows" correspond à "Windows".These comparisons ignore most casing; for example, "windows" matches "Windows". Lors du traitement de caractères ASCII, cette stratégie est équivalente à StringComparison.Ordinal, excepté qu'elle ignore la casse ASCII habituelle.When dealing with ASCII characters, this policy is equivalent to StringComparison.Ordinal, except that it ignores the usual ASCII casing. Par conséquent, tout caractère de la plage [A, Z] (\u0041-\u005A) correspond au caractère correspondant de la plage [a,z] (\u0061-\007A).Therefore, any character in [A, Z] (\u0041-\u005A) matches the corresponding character in [a,z] (\u0061-\007A). La casse hors de la plage ASCII utilise les tables de la culture dite indifférente.Casing outside the ASCII range uses the invariant culture's tables. Par conséquent, la comparaison suivante :Therefore, the following comparison:

String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);
String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase)

est équivalente à la comparaison suivante (mais plus rapide) :is equivalent to (but faster than) this comparison:

String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), 
               StringComparison.Ordinal);
String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), 
               StringComparison.Ordinal)

Ces comparaisons restent très rapides.These comparisons are still very fast.

Notes

StringComparison.OrdinalIgnoreCaseconstitue la meilleure représentation du comportement de chaîne du système de fichiers, des clés de Registre et des valeurs, ainsi que des variables d'environnement.The string behavior of the file system, registry keys and values, and environment variables is best represented by StringComparison.OrdinalIgnoreCase.

StringComparison.Ordinal et StringComparison.OrdinalIgnoreCase utilisent tous les deux directement les valeurs binaires et sont les plus adaptés à la mise en correspondance.Both StringComparison.Ordinal and StringComparison.OrdinalIgnoreCase use the binary values directly, and are best suited for matching. Quand vous n'êtes pas sûr de vos paramètres de comparaison, utilisez l'une de ces deux valeurs.When you are not sure about your comparison settings, use one of these two values. Toutefois, étant donné qu'elles effectuent une comparaison octet par octet, elles n'effectuent pas le tri selon un ordre de tri linguistique (comme un dictionnaire français), mais selon un ordre de tri binaire.However, because they perform a byte-by-byte comparison, they do not sort by a linguistic sort order (like an English dictionary) but by a binary sort order. Les résultats peuvent sembler étranges dans la plupart des contextes s'ils sont affichés aux utilisateurs.The results may look odd in most contexts if displayed to users.

La sémantique ordinale est la valeur par défaut pour les surcharges de String.Equals qui n'incluent pas d'argument StringComparison (notamment l'opérateur d'égalité).Ordinal semantics are the default for String.Equals overloads that do not include a StringComparison argument (including the equality operator). Dans tous les cas, nous vous recommandons d'appeler une surcharge ayant un paramètre StringComparison .In any case, we recommend that you call an overload that has a StringComparison parameter.

opérations de chaîne qui utilisent la culture dite indifférentestring operations that use the invariant culture

Les comparaisons avec la culture dite indifférente utilisent la propriété CompareInfo retournée par la propriété CultureInfo.InvariantCulture statique.Comparisons with the invariant culture use the CompareInfo property returned by the static CultureInfo.InvariantCulture property. Ce comportement est le même sur tous les systèmes ; il traduit tous les caractères en dehors de sa plage en ce qu'il suppose être des caractères invariants équivalents.This behavior is the same on all systems; it translates any characters outside its range into what it believes are equivalent invariant characters. Cette stratégie peut être utile pour la gestion d'un jeu de comportements de chaîne dans toutes les cultures, mais elle donne souvent des résultats inattendus.This policy can be useful for maintaining one set of string behavior across cultures, but it often provides unexpected results.

Les comparaisons ne respectant pas la casse avec la culture dite indifférente utilisent également la propriété CompareInfo statique retournée également par la propriété CultureInfo.InvariantCulture statique pour les informations de comparaison.Case-insensitive comparisons with the invariant culture use the static CompareInfo property returned by the static CultureInfo.InvariantCulture property for comparison information as well. Toutes les différences de casse entre ces caractères traduits sont ignorées.Any case differences among these translated characters are ignored.

Les comparaisons qui utilisent StringComparison.InvariantCulture et StringComparison.Ordinal fonctionnent de la même manière sur les chaînes ASCII.Comparisons that use StringComparison.InvariantCulture and StringComparison.Ordinal work identically on ASCII strings. Toutefois, StringComparison.InvariantCulture prend des décisions linguistiques qui peuvent ne pas être appropriées pour les chaînes qui doivent être interprétées comme un jeu d'octets.However, StringComparison.InvariantCulture makes linguistic decisions that might not be appropriate for strings that have to be interpreted as a set of bytes. L’objet CultureInfo.InvariantCulture.CompareInfo entraîne l’interprétation par la méthode Compare de certains jeux de caractères comme étant équivalents.The CultureInfo.InvariantCulture.CompareInfo object makes the Compare method interpret certain sets of characters as equivalent. Par exemple, l'équivalence suivante est valide dans la culture dite indifférente :For example, the following equivalence is valid under the invariant culture:

InvariantCulture: a + ̊ = åInvariantCulture: a + ̊ = å

Le caractère LETTRE MINUSCULE LATINE A "a" (\u0061), quand il se trouve à côté du caractère DIACRITIQUE ROND EN CHEF " + " ̊" (\u030a), est interprété comme une LETTRE MINUSCULE LATINE A AVEC DIACRITIQUE ROND EN CHEF "å" (\u00e5).The LATIN SMALL LETTER A character "a" (\u0061), when it is next to the COMBINING RING ABOVE character "+ " ̊" (\u030a), is interpreted as the LATIN SMALL LETTER A WITH RING ABOVE character "å" (\u00e5). Comme le montre l'exemple suivant, ce comportement diffère de la comparaison ordinale.As the following example shows, this behavior differs from ordinal comparison.

string separated = "\u0061\u030a";
string combined = "\u00e5";
      
Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}",
                  separated, combined, 
                  String.Compare(separated, combined, 
                                 StringComparison.InvariantCulture) == 0);

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}",
                  separated, combined,
                  String.Compare(separated, combined, 
                                 StringComparison.Ordinal) == 0);
// The example displays the following output:
//    Equal sort weight of a° and å using InvariantCulture: True
//    Equal sort weight of a° and å using Ordinal: False      
Dim separated As String = ChrW(&h61) + ChrW(&h30a)
Dim combined As String = ChrW(&he5)
      
Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}", _
                  separated, combined, _
                  String.Compare(separated, combined, _ 
                                 StringComparison.InvariantCulture) = 0)

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}", _
                  separated, combined, _
                  String.Compare(separated, combined, _
                                 StringComparison.Ordinal) = 0)
' The example displays the following output:
'    Equal sort weight of a° and å using InvariantCulture: True
'    Equal sort weight of a° and å using Ordinal: False

Lors de l’interprétation de noms de fichiers, de cookies ou de tout autre élément dans lequel peut s’afficher une combinaison telle que "å", les comparaisons ordinales offrent toujours le comportement le plus transparent et le plus approprié.When interpreting file names, cookies, or anything else where a combination such as "å" can appear, ordinal comparisons still offer the most transparent and fitting behavior.

En définitive, la culture dite indifférente a très peu de propriétés qui la rendent utile pour la comparaison.On balance, the invariant culture has very few properties that make it useful for comparison. Elle effectue la comparaison d'une manière linguistiquement pertinente, qui l'empêche de garantir une équivalence symbolique complète, mais elle ne constitue pas le choix approprié pour l'affichage dans n'importe quelle culture.It does comparison in a linguistically relevant manner, which prevents it from guaranteeing full symbolic equivalence, but it is not the choice for display in any culture. L'une des rares raisons justifiant l'utilisation de StringComparison.InvariantCulture pour la comparaison est de rendre persistantes des données classées pour un affichage identique dans toutes les cultures.One of the few reasons to use StringComparison.InvariantCulture for comparison is to persist ordered data for a cross-culturally identical display. Par exemple, si un fichier de données volumineux qui contient une liste d'identificateurs triés à des fins d'affichage accompagne une application, un ajout à cette liste nécessiterait une insertion avec un tri de style invariant.For example, if a large data file that contains a list of sorted identifiers for display accompanies an application, adding to this list would require an insertion with invariant-style sorting.

Choix d’un membre StringComparison pour votre appel de méthodeChoosing a StringComparison member for your method call

Le tableau suivant présente le mappage du contexte de chaîne sémantique à un membre d’énumération StringComparison :The following table outlines the mapping from semantic string context to a StringComparison enumeration member:

DonnéesData ComportementBehavior Valeur System.StringComparisonCorresponding System.StringComparison

valeurvalue
Identificateurs internes respectant la casse.Case-sensitive internal identifiers.

Identificateurs respectant la casse dans des normes telles que XML et HTTP.Case-sensitive identifiers in standards such as XML and HTTP.

Paramètres liés à la sécurité respectant la casse.Case-sensitive security-related settings.
Identificateur non linguistique, où les octets correspondent exactement.A non-linguistic identifier, where bytes match exactly. Ordinal
Identificateurs internes ne respectant pas la casse.Case-insensitive internal identifiers.

Identificateurs ne respectant pas la casse dans des normes telles que XML et HTTP.Case-insensitive identifiers in standards such as XML and HTTP.

Chemins d'accès aux fichiers.File paths.

Clés et valeurs de Registre.Registry keys and values.

Variables d'environnement.Environment variables.

Identificateurs de ressource (par exemple, noms de handles).Resource identifiers (for example, handle names).

Paramètres liés à la sécurité ne respectant pas la casse.Case-insensitive security-related settings.
Identificateur non linguistique, où la casse n'est pas pertinente ; en particulier, les données stockées dans la plupart des services système Windows.A non-linguistic identifier, where case is irrelevant; especially data stored in most Windows system services. OrdinalIgnoreCase
Certaines données rendues persistantes et linguistiquement pertinentes.Some persisted, linguistically relevant data.

Affichage de données linguistiques qui nécessitent un ordre de tri fixe.Display of linguistic data that requires a fixed sort order.
Données dont la culture n'est pas spécifiée qui sont toutefois linguistiquement pertinentes.Culturally agnostic data that still is linguistically relevant. InvariantCulture

ou-or-

InvariantCultureIgnoreCase
Données affichées à l'utilisateur.Data displayed to the user.

La plupart des entrées d'utilisateur.Most user input.
Données qui nécessitent des usages linguistiques locaux.Data that requires local linguistic customs. CurrentCulture

ou-or-

CurrentCultureIgnoreCase

Méthodes courantes de comparaison de chaînes dans .NETCommon string comparison methods in .NET

Les sections suivantes décrivent les méthodes le plus souvent utilisées pour la comparaison de chaînes.The following sections describe the methods that are most commonly used for string comparison.

String.CompareString.Compare

Interprétation par défaut : StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

En tant qu'opération la plus centrale de l'interprétation de chaînes, toutes les instances de ces appels de méthode doivent être examinées pour déterminer si les chaînes doivent être interprétées d'après la culture actuelle ou être dissociées de la culture (symboliquement).As the operation most central to string interpretation, all instances of these method calls should be examined to determine whether strings should be interpreted according to the current culture, or dissociated from the culture (symbolically). L'opération appropriée est, en général, la dernière, et une comparaison StringComparison.Ordinal doit être utilisée à la place.Typically, it is the latter, and a StringComparison.Ordinal comparison should be used instead.

La classe System.Globalization.CompareInfo , retournée par la propriété CultureInfo.CompareInfo , inclut également une méthode Compare qui fournit un grand nombre d'options de correspondance (ordinale, ignorance des espaces blancs, ignorance du type Kana, etc.) au moyen de l'énumération d'indicateur CompareOptions .The System.Globalization.CompareInfo class, which is returned by the CultureInfo.CompareInfo property, also includes a Compare method that provides a large number of matching options (ordinal, ignoring white space, ignoring kana type, and so on) by means of the CompareOptions flag enumeration.

String.CompareToString.CompareTo

Interprétation par défaut : StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Cette méthode n'offre actuellement pas de surcharge spécifiant un type StringComparison .This method does not currently offer an overload that specifies a StringComparison type. Il est généralement possible de convertir cette méthode dans la forme String.Compare(String, String, StringComparison) recommandée.It is usually possible to convert this method to the recommended String.Compare(String, String, StringComparison) form.

Les types qui implémentent les interfaces IComparable et IComparable<T> implémentent cette méthode.Types that implement the IComparable and IComparable<T> interfaces implement this method. Étant donné qu'elle n'offre pas la possibilité d'un paramètre StringComparison , les types d'implémentation permettent souvent à l'utilisateur de spécifier un StringComparer dans leur constructeur.Because it does not offer the option of a StringComparison parameter, implementing types often let the user specify a StringComparer in their constructor. L'exemple suivant définit une classe FileName dont le constructeur de classe inclut un paramètre StringComparer .The following example defines a FileName class whose class constructor includes a StringComparer parameter. Cet objet StringComparer est ensuite utilisé dans la méthode FileName.CompareTo .This StringComparer object is then used in the FileName.CompareTo method.

using System;

public class FileName : IComparable
{
   string fname;
   StringComparer comparer; 
   
   public FileName(string name, StringComparer comparer)
   {
      if (String.IsNullOrEmpty(name))
         throw new ArgumentNullException("name");

      this.fname = name;
      
      if (comparer != null)
         this.comparer = comparer;
      else
         this.comparer = StringComparer.OrdinalIgnoreCase;
   }

   public string Name
   {
      get { return fname; }
   }
   
   public int CompareTo(object obj)
   {
      if (obj == null) return 1;

      if (! (obj is FileName))
         return comparer.Compare(this.fname, obj.ToString());
      else
         return comparer.Compare(this.fname, ((FileName) obj).Name);
   }
}
Public Class FileName : Implements IComparable
   Dim fname As String
   Dim comparer As StringComparer 
   
   Public Sub New(name As String, comparer As StringComparer)
      If String.IsNullOrEmpty(name) Then
         Throw New ArgumentNullException("name")
      End If

      Me.fname = name
      
      If comparer IsNot Nothing Then
         Me.comparer = comparer
      Else
         Me.comparer = StringComparer.OrdinalIgnoreCase
      End If      
   End Sub

   Public ReadOnly Property Name As String
      Get
         Return fname
      End Get   
   End Property
   
   Public Function CompareTo(obj As Object) As Integer _
          Implements IComparable.CompareTo
      If obj Is Nothing Then Return 1

      If Not TypeOf obj Is FileName Then
         obj = obj.ToString()
      Else
         obj = CType(obj, FileName).Name
      End If         
      Return comparer.Compare(Me.fname, obj)
   End Function
End Class

String.EqualsString.Equals

Interprétation par défaut : StringComparison.Ordinal.Default interpretation: StringComparison.Ordinal.

La classe String vous permet de tester l'égalité en appelant les surcharges de méthode Equals statique ou d'instance, ou en utilisant l'opérateur d'égalité statique.The String class lets you test for equality by calling either the static or instance Equals method overloads, or by using the static equality operator. Par défaut, les surcharges et l'opérateur utilisent la comparaison ordinale.The overloads and operator use ordinal comparison by default. Toutefois, nous vous recommandons quand même d'appeler une surcharge qui spécifie explicitement le type StringComparison , même si vous voulez effectuer une comparaison ordinale ; cela le simplifie la recherche d'une interprétation de chaîne particulière dans du code.However, we still recommend that you call an overload that explicitly specifies the StringComparison type even if you want to perform an ordinal comparison; this makes it easier to search code for a certain string interpretation.

String.ToUpper et String.ToLowerString.ToUpper and String.ToLower

Interprétation par défaut : StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Vous devez faire preuve de prudence quand vous utilisez ces méthodes, car imposer une majuscule ou une minuscule dans une chaîne est souvent utilisé comme une petite normalisation pour la comparaison de chaînes indépendamment de la casse.You should be careful when you use these methods, because forcing a string to a uppercase or lowercase is often used as a small normalization for comparing strings regardless of case. Si tel est le cas, vous devez envisager d'utiliser une comparaison ne respectant pas la casse.If so, consider using a case-insensitive comparison.

Les méthodes String.ToUpperInvariant et String.ToLowerInvariant sont également disponibles.The String.ToUpperInvariant and String.ToLowerInvariant methods are also available. ToUpperInvariant est le moyen standard de normaliser la casse.ToUpperInvariant is the standard way to normalize case. Les comparaisons faites à l'aide de StringComparison.OrdinalIgnoreCase sont, sur le plan comportemental, la composition de deux appels : appel à ToUpperInvariant sur les deux arguments de chaîne, et exécution d'une comparaison à l'aide de StringComparison.Ordinal.Comparisons made using StringComparison.OrdinalIgnoreCase are behaviorally the composition of two calls: calling ToUpperInvariant on both string arguments, and doing a comparison using StringComparison.Ordinal.

Des surcharges sont également disponibles pour la conversion en majuscules et en minuscules dans une culture spécifique, en passant à la méthode un objet CultureInfo qui représente cette culture.Overloads are also available for converting to uppercase and lowercase in a specific culture, by passing a CultureInfo object that represents that culture to the method.

Char.ToUpper et Char.ToLowerChar.ToUpper and Char.ToLower

Interprétation par défaut : StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Ces méthodes fonctionnent de la même façon que les méthodes String.ToUpper et String.ToLower décrites dans la section précédente.These methods work similarly to the String.ToUpper and String.ToLower methods described in the previous section.

String.StartsWith et String.EndsWithString.StartsWith and String.EndsWith

Interprétation par défaut : StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Par défaut, ces deux méthodes effectuent une comparaison dépendante de la culture.By default, both of these methods perform a culture-sensitive comparison.

String.IndexOf et String.LastIndexOfString.IndexOf and String.LastIndexOf

Interprétation par défaut : StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

La façon dont les surcharges par défaut de ces méthodes effectuent les comparaisons n'est pas cohérente.There is a lack of consistency in how the default overloads of these methods perform comparisons. Toutes les méthodes String.IndexOf et String.LastIndexOf qui incluent un paramètre Char effectuent une comparaison ordinale, mais les méthodes String.IndexOf et String.LastIndexOf par défaut qui incluent un paramètre String effectuent une comparaison dépendante de la culture.All String.IndexOf and String.LastIndexOf methods that include a Char parameter perform an ordinal comparison, but the default String.IndexOf and String.LastIndexOf methods that include a String parameter perform a culture-sensitive comparison.

Si vous appelez la méthode String.IndexOf(String) ou String.LastIndexOf(String) et que vous lui passez une chaîne à localiser dans l'instance actuelle, nous vous recommandons d'appeler une surcharge qui spécifie explicitement le type StringComparison .If you call the String.IndexOf(String) or String.LastIndexOf(String) method and pass it a string to locate in the current instance, we recommend that you call an overload that explicitly specifies the StringComparison type. Les surcharges qui incluent un argument Char ne vous permettent pas de spécifier un type StringComparison .The overloads that include a Char argument do not allow you to specify a StringComparison type.

Méthodes qui effectuent indirectement la comparaison de chaînesMethods that perform string comparison indirectly

Certaines méthodes autres que les méthodes de chaîne dont l'opération centrale est la comparaison de chaînes utilisent le type StringComparer .Some non-string methods that have string comparison as a central operation use the StringComparer type. La classe StringComparer inclut six propriétés statiques qui retournent des instances de StringComparer dont les méthodes StringComparer.Compare effectuent les types de comparaisons de chaînes suivants :The StringComparer class includes six static properties that return StringComparer instances whose StringComparer.Compare methods perform the following types of string comparisons:

Array.Sort et Array.BinarySearchArray.Sort and Array.BinarySearch

Interprétation par défaut : StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Quand vous stockez des données dans une collection ou quand vous lisez des données persistantes à partir d’un fichier ou d’une base de données dans une collection, le changement de culture actuelle peut invalider les invariants de la collection.When you store any data in a collection, or read persisted data from a file or database into a collection, switching the current culture can invalidate the invariants in the collection. La méthode Array.BinarySearch suppose que les éléments du tableau dans lequel effectuer la recherche sont déjà triés.The Array.BinarySearch method assumes that the elements in the array to be searched are already sorted. Pour trier tout élément de chaîne dans le tableau, la méthode Array.Sort appelle la méthode String.Compare pour classer les éléments individuels.To sort any string element in the array, the Array.Sort method calls the String.Compare method to order individual elements. L'utilisation d'un comparateur dépendant de la culture peut s'avérer dangereux si la culture change entre le moment où le tableau est trié et le moment où son contenu fait l'objet d'une recherche.Using a culture-sensitive comparer can be dangerous if the culture changes between the time that the array is sorted and its contents are searched. Par exemple, dans le code suivant, le stockage et la récupération fonctionnent sur le comparateur fourni implicitement par la propriété Thread.CurrentThread.CurrentCulture.For example, in the following code, storage and retrieval operate on the comparer that is provided implicitly by the Thread.CurrentThread.CurrentCulture property. Si la culture peut changer entre les appels à StoreNames et DoesNameExist, et surtout si le contenu du tableau est rendu persistant à un moment donné entre les deux appels de méthode, la recherche binaire peut échouer.If the culture can change between the calls to StoreNames and DoesNameExist, and especially if the array contents are persisted somewhere between the two method calls, the binary search may fail.

// Incorrect.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names); // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name) >= 0);  // Line B.
}
' Incorrect.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names)          ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name) >= 0      ' Line B.
End Function

L'exemple suivant, qui utilise la même méthode de comparaison ordinale (indépendante de la culture) pour trier le tableau et pour effectuer une recherche, présente une variation recommandée.A recommended variation appears in the following example, which uses the same ordinal (culture-insensitive) comparison method both to sort and to search the array. Le code de modification est reflété dans les lignes libellées Line A et Line B dans les deux exemples.The change code is reflected in the lines labeled Line A and Line B in the two examples.

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.Ordinal);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.Ordinal) >= 0);  // Line B.
}
' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names, StringComparer.Ordinal)           ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name, StringComparer.Ordinal) >= 0      ' Line B.
End Function

Si ces données sont rendues persistantes et déplacées dans toutes les cultures, et que le tri est utilisé pour présenter ces données à l'utilisateur, vous pouvez envisager d'utiliser StringComparison.InvariantCulture, qui fonctionne linguistiquement pour une meilleure sortie d'utilisateur mais n'est pas affecté par les modifications apportées à la culture.If this data is persisted and moved across cultures, and sorting is used to present this data to the user, you might consider using StringComparison.InvariantCulture, which operates linguistically for better user output but is unaffected by changes in culture. L'exemple suivant modifie les deux exemples précédents pour utiliser la culture dite indifférente pour le tri du tableau et la recherche dans celui-ci.The following example modifies the two previous examples to use the invariant culture for sorting and searching the array.

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.InvariantCulture);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.InvariantCulture) >= 0);  // Line B.
}
' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names, StringComparer.InvariantCulture)           ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name, StringComparer.InvariantCulture) >= 0      ' Line B.
End Function

Exemple de collections : constructeur HashtableCollections example: Hashtable constructor

Le hachage de chaînes constitue un deuxième exemple d'opération qui est affectée par la façon dont des chaînes sont comparées.Hashing strings provides a second example of an operation that is affected by the way in which strings are compared.

L'exemple suivant instancie un objet Hashtable en lui passant l'objet StringComparer qui est retourné par la propriété StringComparer.OrdinalIgnoreCase .The following example instantiates a Hashtable object by passing it the StringComparer object that is returned by the StringComparer.OrdinalIgnoreCase property. Étant donné qu'une classe StringComparer dérivée de StringComparer implémente l'interface IEqualityComparer , sa méthode GetHashCode est utilisée pour calculer le code de hachage de chaînes dans la table de hachage.Because a class StringComparer that is derived from StringComparer implements the IEqualityComparer interface, its GetHashCode method is used to compute the hash code of strings in the hash table.

const int initialTableCapacity = 100;
Hashtable h;

public void PopulateFileTable(string directory)
{
   h = new Hashtable(initialTableCapacity, 
                     StringComparer.OrdinalIgnoreCase);
         
   foreach (string file in Directory.GetFiles(directory))
         h.Add(file, File.GetCreationTime(file));
}

public void PrintCreationTime(string targetFile)
{
   Object dt = h[targetFile];
   if (dt != null)
   {
      Console.WriteLine("File {0} was created at time {1}.",
         targetFile, 
         (DateTime) dt);
   }
   else
   {
      Console.WriteLine("File {0} does not exist.", targetFile);
   }
}
Const initialTableCapacity As Integer = 100
Dim h As Hashtable

Public Sub PopulateFileTable(dir As String)
   h = New Hashtable(initialTableCapacity, _
                     StringComparer.OrdinalIgnoreCase)
                     
   For Each filename As String In Directory.GetFiles(dir)
      h.Add(filename, File.GetCreationTime(filename))
   Next                        
End Sub

Public Sub PrintCreationTime(targetFile As String)
   Dim dt As Object = h(targetFile)
   If dt IsNot Nothing Then
      Console.WriteLine("File {0} was created at {1}.", _
         targetFile, _
         CDate(dt))
   Else
      Console.WriteLine("File {0} does not exist.", targetFile)
   End If
End Sub  

Affichage et persistance des données mises en formeDisplaying and persisting formatted data

Lorsque vous affichez des données non-chaînées telles que les nombres et les dates et heures aux utilisateurs, mettez-les en forme en utilisant les paramètres de la culture de l'utilisateur.When you display non-string data such as numbers and dates and times to users, format them by using the user's cultural settings. Par défaut, tous les éléments suivants utilisent la culture du thread actuelle dans les opérations de mise en forme :By default, the following all use the current thread culture in formatting operations:

  • Chaînes interpolées prises en charge par les compilateurs C# et Visual Basic.Interpolated strings supported by the C# and Visual Basic compilers.
  • Opérations de concaténation de chaîne qui utilisent les opérateurs de concaténation C# ou Visual Basic, ou qui appellent directement la méthode String.Concat.String concatenation operations that use the C# or Visual Basic concatenation operators or that call the String.Concat method directly.
  • Méthode String.FormatThe String.Format method.
  • Méthodes ToString des types numériques et des types de date et d’heure.The ToString methods of the numeric types and the date and time types.

Pour spécifier explicitement qu’une chaîne doit être mise en forme en utilisant les conventions d’une culture désignée ou de la culture invariante, vous pouvez procéder comme suit :To explicitly specify that a string should be formatted by using the conventions of a designated culture or the invariant culture, you can do the following:

  • Quand vous utilisez les méthodes String.Format et ToString, appelez une surcharge qui a un paramètre provider, tel que String.Format(IFormatProvider, String, Object[]) ou DateTime.ToString(IFormatProvider) et passez-lui la propriété CultureInfo.CurrentCulture, une instance CultureInfo qui représente la culture souhaitée, ou la propriété CultureInfo.InvariantCulture.When using the String.Format and ToString methods, call an overload that has a provider parameter, such as String.Format(IFormatProvider, String, Object[]) or DateTime.ToString(IFormatProvider), and pass it the CultureInfo.CurrentCulture property, a CultureInfo instance that represents the desired culture, or the CultureInfo.InvariantCulture property.

  • Pour la concaténation de chaîne, n’autorisez pas le compilateur à effectuer de conversions implicites.For string concatenation, do not allow the compiler to perform any implicit conversions. Au lieu de cela, effectuez une conversion explicite en appelant une surcharge ToString ayant un paramètre provider.Instead, perform an explicit conversion by calling a ToString overload that has a provider parameter. Par exemple, le compilateur utilise implicitement la culture actuelle lors de la conversion d’une valeur Double en une chaîne dans le code C# suivant :For example, the compiler implicitly uses the current culture when converting a Double value to a string in the following C# code:

    string concat1 = "The amount is " + 126.03 + ".";
    Console.WriteLine(concat1);
    

    Au lieu de cela, vous pouvez spécifier explicitement la culture dont les conventions de mise en forme sont utilisées dans la conversion en appelant la méthode Double.ToString(IFormatProvider), comme illustré par le code C# suivant :Instead, you can explicitly specify the culture whose formatting conventions are used in the conversion by calling the Double.ToString(IFormatProvider) method, as the following C# code does:

    string concat2 = "The amount is " + 126.03.ToString(CultureInfo.InvariantCulture) + ".";
    Console.WriteLine(concat2);
    
  • Pour l’interpolation de chaîne, plutôt que d’affecter une chaîne interpolée à une instance String, affectez-la à un élément FormattableString.For string interpolation, rather than assigning an interpolated string to a String instance, assign it to a FormattableString. Vous pouvez ensuite appeler sa méthode FormattableString.ToString() pour produire une chaîne de résultat qui reflète les conventions de la culture actuelle, ou vous pouvez appeler la méthode FormattableString.ToString(IFormatProvider) pour produire une chaîne de résultat qui reflète les conventions d’une culture spécifiée.You can then call its FormattableString.ToString() method produce a result string that reflects the conventions of the current culture, or you can call the FormattableString.ToString(IFormatProvider) method to produce a result string that reflects the conventions of a specified culture. Vous pouvez également transmettre la chaîne pouvant être mise en forme à la méthode FormattableString.Invariant statique pour produire une chaîne de résultat qui reflète les conventions de la culture invariante.You can also pass the formattable string to the static FormattableString.Invariant method to produce a result string that reflects the conventions of the invariant culture. L'exemple suivant illustre cette approche.The following example illustrates this approach. (La sortie de l’exemple correspond à la culture actuelle en-US.)(The output from the example reflects a current culture of en-US.)

    using System;
    using System.Globalization;
    
    class Program
    {
        static void Main()
        {
            Decimal value = 126.03m;
            FormattableString amount = $"The amount is {value:C}"; 
            Console.WriteLine(amount.ToString());
            Console.WriteLine(amount.ToString(new CultureInfo("fr-FR")));
            Console.WriteLine(FormattableString.Invariant(amount));
        }
    }
    // The example displays the following output:
    //    The amount is $126.03
    //    The amount is 126,03 €
    //    The amount is ¤126.03
    
    Imports System.Globalization
    
    Module Program
        Sub Main()
            Dim value As Decimal = 126.03
            Dim amount As FormattableString = $"The amount is {value:C}" 
            Console.WriteLine(amount.ToString())
            Console.WriteLine(amount.ToString(new CultureInfo("fr-FR")))
            Console.WriteLine(FormattableString.Invariant(amount))
        End Sub
    End Module
    ' The example displays the following output:
    '    The amount is $126.03
    '    The amount is 126,03 €
    '    The amount is ¤126.03
    

Vous pouvez rendre persistantes des données non-chaînées soit comme données binaires, soit comme données mises en forme.You can persist non-string data either as binary data or as formatted data. Si vous choisissez de l'enregistrer en tant que données mises en forme, vous devez appeler une surcharge de méthode de mise en forme qui inclut un paramètre provider et le passer à la propriété CultureInfo.InvariantCulture .If you choose to save it as formatted data, you should call a formatting method overload that includes a provider parameter and pass it the CultureInfo.InvariantCulture property. La culture dite indifférente fournit un format cohérent pour les données mises en forme qui est indépendant de la culture et de l'ordinateur.The invariant culture provides a consistent format for formatted data that is independent of culture and machine. En revanche, assurer la persistance de données mises en forme à l'aide de cultures autres que la culture dite indifférente a plusieurs limites :In contrast, persisting data that is formatted by using cultures other than the invariant culture has a number of limitations:

  • Les données seront vraisemblablement inutilisables si elles sont récupérées sur un système ayant une autre culture, ou si l'utilisateur du système actuel change la culture actuelle et essaie de récupérer les données.The data is likely to be unusable if it is retrieved on a system that has a different culture, or if the user of the current system changes the current culture and tries to retrieve the data.
  • Les propriétés d'une culture sur un ordinateur spécifique peuvent différer des valeurs standard.The properties of a culture on a specific computer can differ from standard values. À tout moment, un utilisateur peut personnaliser les paramètres d'affichage selon la culture.At any time, a user can customize culture-sensitive display settings. De ce fait, les données mises en forme sont stockées sur un système et peuvent ne pas être lisibles lorsque l'utilisateur personnalise les paramètres de culture.Because of this, formatted data that is saved on a system may not be readable after the user customizes cultural settings. La portabilité des données mises en forme sur différents ordinateurs peut être encore plus limitée.The portability of formatted data across computers is likely to be even more limited.
  • Des normes internationales, régionales ou nationales qui régissent la mise en forme des nombres ou des dates et heures évoluent au fil du temps, et ces modifications sont intégrées dans les mises à jour du système d'exploitation Windows.International, regional, or national standards that govern the formatting of numbers or dates and times change over time, and these changes are incorporated into Windows operating system updates. Quand les conventions de mise en forme changent, les données qui ont été mises en forme en utilisant les conventions antérieures peuvent devenir illisibles.When formatting conventions change, data that was formatted by using the previous conventions may become unreadable.

L'exemple suivant illustre la portabilité limitée qui résulte de l'utilisation de la mise en forme qui tient compte de la culture pour assurer la persistance des données.The following example illustrates the limited portability that results from using culture-sensitive formatting to persist data. L'exemple enregistre un tableau de valeurs de date et d'heure dans un fichier.The example saves an array of date and time values to a file. Celles-ci sont mises en forme en utilisant les conventions culturelles de l'anglais (États-Unis).These are formatted by using the conventions of the English (United States) culture. Une fois que l'application change la culture du thread actuel pour appliquer le français (Suisse), elle essaie de lire les valeurs enregistrées en utilisant les conventions de mise en forme de la culture actuelle.After the application changes the current thread culture to French (Switzerland), it tries to read the saved values by using the formatting conventions of the current culture. La tentative de lecture des éléments de données par deux fois renvoie une exception FormatException , et le tableau de dates contient maintenant deux éléments incorrects qui sont identiques à MinValue.The attempt to read two of the data items throws a FormatException exception, and the array of dates now contains two incorrect elements that are equal to MinValue.

using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;

public class Example
{
   private static string filename = @".\dates.dat";

   public static void Main()
   {
      DateTime[] dates = { new DateTime(1758, 5, 6, 21, 26, 0), 
                           new DateTime(1818, 5, 5, 7, 19, 0), 
                           new DateTime(1870, 4, 22, 23, 54, 0),  
                           new DateTime(1890, 9, 8, 6, 47, 0), 
                           new DateTime(1905, 2, 18, 15, 12, 0) }; 
      // Write the data to a file using the current culture.
      WriteData(dates);
      // Change the current culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH");
      // Read the data using the current culture.
      DateTime[] newDates = ReadData();
      foreach (var newDate in newDates)
         Console.WriteLine(newDate.ToString("g"));
   }
   
   private static void WriteData(DateTime[] dates) 
   {
      StreamWriter sw = new StreamWriter(filename, false, Encoding.UTF8);    
      for (int ctr = 0; ctr < dates.Length; ctr++) {
         sw.Write("{0}", dates[ctr].ToString("g", CultureInfo.CurrentCulture));
         if (ctr < dates.Length - 1) sw.Write("|");   
      }      
      sw.Close();
   }
   
   private static DateTime[] ReadData() 
   {
      bool exceptionOccurred = false;
           
      // Read file contents as a single string, then split it.
      StreamReader sr = new StreamReader(filename, Encoding.UTF8);
      string output = sr.ReadToEnd();
      sr.Close();   

      string[] values = output.Split( new char[] { '|' } );
      DateTime[] newDates = new DateTime[values.Length]; 
      for (int ctr = 0; ctr < values.Length; ctr++) {
         try {
            newDates[ctr] = DateTime.Parse(values[ctr], CultureInfo.CurrentCulture);
         }
         catch (FormatException) {
            Console.WriteLine("Failed to parse {0}", values[ctr]);
            exceptionOccurred = true;
         }
      }      
      if (exceptionOccurred) Console.WriteLine();
      return newDates;
   }
}
// The example displays the following output:
//       Failed to parse 4/22/1870 11:54 PM
//       Failed to parse 2/18/1905 3:12 PM
//       
//       05.06.1758 21:26
//       05.05.1818 07:19
//       01.01.0001 00:00
//       09.08.1890 06:47
//       01.01.0001 00:00
//       01.01.0001 00:00
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Threading

Module Example
   Private filename As String = ".\dates.dat"
   
   Public Sub Main()
      Dim dates() As Date = { #5/6/1758 9:26PM#, #5/5/1818 7:19AM#, _ 
                              #4/22/1870 11:54PM#, #9/8/1890 6:47AM#, _ 
                              #2/18/1905 3:12PM# }
      ' Write the data to a file using the current culture.
      WriteData(dates)
      ' Change the current culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH")
      ' Read the data using the current culture.
      Dim newDates() As Date = ReadData()
      For Each newDate In newDates
         Console.WriteLine(newDate.ToString("g"))
      Next
   End Sub
   
   Private Sub WriteData(dates() As Date)
      Dim sw As New StreamWriter(filename, False, Encoding.Utf8)    
      For ctr As Integer = 0 To dates.Length - 1
         sw.Write("{0}", dates(ctr).ToString("g", CultureInfo.CurrentCulture))
         If ctr < dates.Length - 1 Then sw.Write("|")   
      Next      
      sw.Close()
   End Sub
   
   Private Function ReadData() As Date()
      Dim exceptionOccurred As Boolean = False
           
      ' Read file contents as a single string, then split it.
      Dim sr As New StreamReader(filename, Encoding.Utf8)
      Dim output As String = sr.ReadToEnd()
      sr.Close()   

      Dim values() As String = output.Split( {"|"c } )
      Dim newDates(values.Length - 1) As Date 
      For ctr As Integer = 0 To values.Length - 1
         Try
            newDates(ctr) = DateTime.Parse(values(ctr), CultureInfo.CurrentCulture)
         Catch e As FormatException
            Console.WriteLine("Failed to parse {0}", values(ctr))
            exceptionOccurred = True
         End Try
      Next      
      If exceptionOccurred Then Console.WriteLine()
      Return newDates
   End Function
End Module
' The example displays the following output:
'       Failed to parse 4/22/1870 11:54 PM
'       Failed to parse 2/18/1905 3:12 PM
'       
'       05.06.1758 21:26
'       05.05.1818 07:19
'       01.01.0001 00:00
'       09.08.1890 06:47
'       01.01.0001 00:00
'       01.01.0001 00:00
'

Toutefois, si vous remplacez la propriété CultureInfo.CurrentCulture par CultureInfo.InvariantCulture dans les appels à DateTime.ToString(String, IFormatProvider) et DateTime.Parse(String, IFormatProvider), les données de date et d’heure persistantes sont correctement restaurées, comme le montre la sortie suivante :However, if you replace the CultureInfo.CurrentCulture property with CultureInfo.InvariantCulture in the calls to DateTime.ToString(String, IFormatProvider) and DateTime.Parse(String, IFormatProvider), the persisted date and time data is successfully restored, as the following output shows:

06.05.1758 21:26
05.05.1818 07:19
22.04.1870 23:54
08.09.1890 06:47
18.02.1905 15:12

Voir aussiSee also