Recherche…


Remarques

Dans les chaînes .NET, System.String est une séquence de caractères System.Char , chaque caractère est une unité de code codée UTF-16. Cette distinction est importante car la définition du caractère dans la langue parlée et la définition du caractère .NET (et de nombreuses autres langues) sont différentes.

Un caractère , qui devrait être correctement appelé grapheme , est affiché comme un glyphe et est défini par un ou plusieurs points de code Unicode. Chaque point de code est ensuite codé dans une séquence d' unités de code . Maintenant, il devrait être clair pourquoi un seul System.Char ne représente pas toujours un graphème, voyons dans la réalité comment ils sont différents:

  • Un graphème, en raison de la combinaison de caractères , peut donner deux ou plusieurs points de code: à est composé de deux points de code: U + 0061 LETTRE MINUSCULE LATINE A et U + 0300 COMBINING ACCENT ACCENT . C'est l'erreur la plus courante car "à".Length == 2 alors que vous pouvez vous attendre à 1 .
  • Il y a des caractères dupliqués, par exemple à peut être un seul point de code U + 00E0 LATIN SMALL LETTER A AVEC GRAVE ou deux points de code comme expliqué ci-dessus. Évidemment, ils doivent comparer le même: "\u00e0" == "\u0061\u0300" (même si "\u00e0".Length != "\u0061\u0300".Length ). Cela est possible en raison de la normalisation de chaîne effectuée par la méthode String.Normalize() .
  • Une séquence Unicode peut contenir une séquence composée ou décomposé, par exemple le caractère U + D55C HAN caractère peut être un seul point de code (codé comme un seul code-unité UTF-16) ou une séquence décomposée de ses syllabes ᄒ, et . Ils doivent être comparés à égalité.
  • Un point de code peut être codé en plusieurs unités de code: caractère 𠂊 U + 2008A HAN CHARACTER est codé sous la forme de deux System.Char ( "\ud840\udc8a" ) même s'il ne s'agit que d'un seul point de code: UTF-16 l'encodage n'est pas de taille fixe! Ceci est une source d'innombrables bogues (également des bogues de sécurité sérieux), si par exemple votre application applique une longueur maximale et tronque aveuglément la chaîne à ce moment-là, vous pouvez créer une chaîne non valide.
  • Certaines langues ont un digraphe et des trigraphes, par exemple en tchèque ch est une lettre autonome (après h et avant i, lorsque vous commandez une liste de chaînes, vous aurez fyzika avant chimie .

Il y a beaucoup plus de problèmes concernant la gestion du texte, voir par exemple Comment puis-je effectuer une comparaison caractère par caractère compatible avec Unicode? pour une introduction plus large et plus de liens vers des arguments connexes.

En général, lorsque vous traitez du texte international, vous pouvez utiliser cette fonction simple pour énumérer des éléments de texte dans une chaîne (en évitant de casser les substituts et l’encodage Unicode):

public static class StringExtensions
{
    public static IEnumerable<string> EnumerateCharacters(this string s)
    {
        if (s == null)
            return Enumerable.Empty<string>();

        var enumerator = StringInfo.GetTextElementEnumerator(s.Normalize());
        while (enumerator.MoveNext())
            yield return (string)enumerator.Value;
    }
}

Compter des caractères distincts

Si vous avez besoin de compter des caractères distincts, pour les raisons expliquées dans la section Notes , vous ne pouvez pas simplement utiliser la propriété Length parce que c'est la longueur du tableau de System.Char qui ne sont pas des caractères mais des unités de code ni graphèmes). Si, par exemple, vous écrivez simplement du text.Distinct().Count() vous obtiendrez des résultats incorrects, corrigez le code:

int distinctCharactersCount = text.EnumerateCharacters().Count();

Une étape supplémentaire consiste à compter les occurrences de chaque caractère , si les performances ne sont pas un problème, vous pouvez simplement le faire comme ça (dans cet exemple indépendamment du cas):

var frequencies = text.EnumerateCharacters()
    .GroupBy(x => x, StringComparer.CurrentCultureIgnoreCase)
    .Select(x => new { Character = x.Key, Count = x.Count() };

Compter les caractères

Si vous avez besoin de compter des caractères , pour les raisons expliquées dans la section Notes , vous ne pouvez pas simplement utiliser la propriété Length parce que c'est la longueur du tableau de System.Char qui ne sont pas des caractères mais des unités de code graphèmes). Le code correct est alors:

int length = text.EnumerateCharacters().Count();

Une petite optimisation peut réécrire spécifiquement la méthode d’extension EnumerateCharacters() à cette fin:

public static class StringExtensions
{
    public static int CountCharacters(this string text)
    {
        if (String.IsNullOrEmpty(text))
            return 0;

        int count = 0;
        var enumerator = StringInfo.GetTextElementEnumerator(text);
        while (enumerator.MoveNext())
            ++count;

        return count;
    }
}

Compter les occurrences d'un caractère

En raison des raisons expliquées dans la section Remarques , vous ne pouvez pas simplement faire cela (sauf si vous voulez compter les occurrences d'une unité de code spécifique):

int count = text.Count(x => x == ch);

Vous avez besoin d'une fonction plus complexe:

public static int CountOccurrencesOf(this string text, string character)
{
    return text.EnumerateCharacters()
        .Count(x => String.Equals(x, character, StringComparer.CurrentCulture));
}

Notez que la comparaison de chaînes (contrairement à la comparaison de caractères qui est invariante par culture) doit toujours être effectuée conformément aux règles d'une culture spécifique.

Fendre la chaîne en blocs de longueur fixe

Nous ne pouvons pas briser une chaîne en points arbitraires (parce qu'un System.Char peut ne pas être valide seul parce qu'il est un personnage combinant ou partie d'un substitut) puis le code doit tenir compte (notez que avec la longueur que je veux dire le nombre de graphèmes pas nombre d' unités de code ):

public static IEnumerable<string> Split(this string value, int desiredLength)
{
    var characters = StringInfo.GetTextElementEnumerator(value);
    while (characters.MoveNext())
        yield return String.Concat(Take(characters, desiredLength));
}

private static IEnumerable<string> Take(TextElementEnumerator enumerator, int count)
{
    for (int i = 0; i < count; ++i)
    {
        yield return (string)enumerator.Current;

        if (!enumerator.MoveNext())
            yield break;
    }
}

Convertir une chaîne vers / depuis un autre encodage

Les chaînes .NET contiennent System.Char (unités de code UTF-16). Si vous souhaitez enregistrer (ou gérer) du texte avec un autre encodage, vous devez utiliser un tableau de System.Byte .

Les conversions sont effectuées par des classes dérivées de System.Text.Encoder et System.Text.Decoder qui, ensemble, peuvent convertir vers / depuis un autre codage ( à partir d' une matrice codée octet X byte[] à une UTF-16 codé System.String et vice -versa).

Comme l'encodeur / décodeur fonctionne généralement très près les uns des autres, ils sont regroupés dans une classe dérivée de System.Text.Encoding , les classes dérivées offrent des conversions vers / depuis les encodages courants (UTF-8, UTF-16, etc.).

Exemples:

Convertir une chaîne en UTF-8

byte[] data = Encoding.UTF8.GetBytes("This is my text");

Convertir des données UTF-8 en chaîne

var text = Encoding.UTF8.GetString(data);

Modifier l'encodage d'un fichier texte existant

Ce code lit le contenu d'un fichier texte encodé en UTF-8 et le sauvegarde sous forme de code UTF-16. Notez que ce code n'est pas optimal si le fichier est gros car il lira tout son contenu en mémoire:

var content = File.ReadAllText(path, Encoding.UTF8);
File.WriteAllText(content, Encoding.UTF16);

Méthode virtuelle Object.ToString ()

Tout dans .NET est un objet, donc chaque type a la méthode ToString() définie dans la classe Object qui peut être remplacée. L'implémentation par défaut de cette méthode renvoie simplement le nom du type:

public class Foo
{
}

var foo = new Foo();
Console.WriteLine(foo); // outputs Foo

ToString() est implicitement appelé lors de la concaténation de la valeur avec une chaîne:

public class Foo
{
    public override string ToString()
    {
        return "I am Foo";
    }
}

var foo = new Foo();
Console.WriteLine("I am bar and "+foo);// outputs I am bar and I am Foo

Le résultat de cette méthode est également largement utilisé par les outils de débogage. Si, pour une raison quelconque, vous ne souhaitez pas remplacer cette méthode, mais souhaitez personnaliser la manière dont le débogueur affiche la valeur de votre type, utilisez l' attribut DebuggerDisplay ( MSDN ):

// [DebuggerDisplay("Person = FN {FirstName}, LN {LastName}")]
[DebuggerDisplay("Person = FN {"+nameof(Person.FirstName)+"}, LN {"+nameof(Person.LastName)+"}")]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set;}
    // ...
}

Immuabilité des cordes

Les chaînes sont immuables. Vous ne pouvez pas changer la chaîne existante. Toute opération sur la chaîne crée une nouvelle instance de la chaîne ayant une nouvelle valeur. Cela signifie que si vous devez remplacer un seul caractère dans une chaîne très longue, la mémoire sera allouée pour une nouvelle valeur.

string veryLongString = ...
// memory is allocated
string newString = veryLongString.Remove(0,1); // removes first character of the string.

Si vous devez effectuer de nombreuses opérations avec une valeur de chaîne, utilisez la classe StringBuilder conçue pour une manipulation efficace des chaînes:

var sb = new StringBuilder(someInitialString);
foreach(var str in manyManyStrings)
{
    sb.Append(str);
} 
var finalString = sb.ToString();

Сomparer les chaînes

Malgré que String soit un type de référence, l'opérateur == compare les valeurs de chaîne plutôt que les références.

Comme vous le savez peut-être, string n'est qu'un tableau de caractères. Mais si vous pensez que le contrôle et la comparaison de l’égalité des cordes sont rendus caractère par caractère, vous vous trompez. Cette opération est spécifique à la culture (voir Remarques ci-dessous): certaines séquences de caractères peuvent être considérées comme égales en fonction de la culture .

Réfléchissez à deux fois avant de court-circuiter le contrôle de l'égalité en comparant les propriétés de Length de deux chaînes!

Utilisez des surcharges de la méthode String.Equals qui acceptent une valeur d' énumération StringComparison supplémentaire, si vous devez modifier le comportement par défaut.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow