[.NET] Comprendre le concept de la gestion du codage des caractères sous .NET

Une question de débutant récurrente dans les forums Microsoft : « Comment convertir une chaîne de caractères Unicode en ASCII sous .NET »

La MAUVAISE réponse que l’on trouve sur pas mal de forums est la suivante : « Utilisez cette méthode :  »

public static string Convertir(string chaine, Encoding codage)
{
 byte[] b;

 b = Encoding.Unicode.GetBytes(chaine);

 return codage.GetString(b);
}
Public Shared Function Convertir(ByVal chaine As String, ByVal codage As Encoding)
Dim b() As Byte

b = Encoding.Unicode.GetBytes(chaine)

Return codage.GetString(b)
End Function

Imprimer le code ci-dessous sur une feuille de papier A4, écrivez en-dessous « A BANNIR » et mettez la feuille à la place de la photo de vos enfants sur votre bureau !!!

Le processus de traitement d’une chaîne de caractères.

Le processus simple d’un traitement d’une chaîne de caractères en programmation peut se résumer ainsi :

Schéma du flux d'utilisation d'une chaîne de caractère

Les étapes de ce processus sont les suivantes :

  1. On lit les chaines de caractères à partir d’une source de données (Fichier, SGBD, Socket,…etc)
  2. Les chaînes de caractères lues sont stockées en mémoire.
  3. On traite les chaînes de caractères en mémoire.
  4. Une fois que l’on a terminé le traitement, on écrit les chaines de caractères dans une source de données (identique ou différente).

Un exemple simple de ce processus, on lit l’adresse postale d’un client à partir d’un fichier, on la modifie et on la réécrit dans le fichier.

Toutes les sources de données stockent les chaines de caractères sous forme de séquence d’octets.
Une représentation de ces chaînes en octets est donc nécessaire, on appelle cela le codage de caractère (ou jeu de caractères).

Le processus de transformation d’une chaîne de caractères en octets s’appelle : Le codage (ou décodage pour le processus inverse).

Il existe beaucoup de jeu de caractères (Unicode, ASCII, EBCDIC, …etc). Lorsque l’on développe une application sous .NET, on se retrouve confronté aux problèmes suivants :

  • Comment exploiter une source de données qui manipule un jeu de caractère différent de celui de .NET ?
  • Comment puis-je envoyer des chaînes de caractères à une source de données qui ne supporte pas le jeu de caractères de .NET ?

Les chaînes de caractères du .NET = Unicode UTF-16

Lors de la conception de .NET, Microsoft a du choisir un codage qui répond à ces besoins :

  • Qui soit normalisé (Interopérable)
  • Qui représente tous les caractères de toutes les langues.
  • Qui soit représenté en octet de façon la plus compacte possible.

Microsoft a donc choisi l’encodage Unicode UTF-16.

Toutes les chaînes de caractères (System.String) en mémoire que vous manipulez sous .NET sont donc OBLIGATOIREMENT des chaînes de caractères qui sont codées sous Unicode UTF-16.

Or, il y a de fortes chances que les chaînes de caractères de vos sources de données (d’entrées et de sorties), soient représentées différemment.
Pour remédier à ce problème, Microsoft propose dans le .NET de traiter ce problème en amont et en aval du processus de traitement d’une chaîne de caractères.

Coder et décoder en amont et en aval

Si l’on reprend le schéma précédent, on s’aperçoit que le seul moment où il y a un codage c’est au niveau de l’écriture d’une chaîne de caractères sur une source de données (où à la lecture dans le cas contraire). On transforme alors une chaîne de caractères .NET (Unicode) en une séquence d’octets correspondant au codage utilisé par la source de données.

Cette transformation est réalisée par un « wrapper » de chaîne de caractères. Un wrapper pour le codage, prend en entrée une chaîne de caractères .NET et la transforme en tableau d’octets (System.Byte). Pour le décodage le procédé est le même mais à l’envers.

On trouve beaucoup de wrapper de chaîne de caractères de façon implicite dans le .NET Framework. Par exemple :

  • System.IO.StreamReader est un wrapper basique permettant de lire un flux d’octet en fonction d’un codage de jeu de caractères.
  • System.Web.Protocols.HttpSimpleClientProtocol permet de comuniquer avec un WebService et possède une propriété « RequestEncoding » spécifiant le codage de caractères renvoyé par le serveur.
  • System.Web.UI.Page contient une propriété ResponseEncoding spécifiant dans quel codage de caractères sera générée la page XHMTL.

Toutes ces classes sont indirectement des wrappers de chaînes de caractères, en effet vous constatez qu’elles prennent « en entrées » des chaînes de caractères .NET (Unicode UTF-16) et produise au final un flux d’octet.

Par exemple : Avec la classe System.Web.UI.Page, vous lui donné à manger des chaînes de caractères (propriété Text des contrôles par exemple) et au final la page généré sera un flux d’octets envoyé au client.

Gardez donc toujours en tête que le wrapper, doit toujours convertir un flux d’octets en une chaine de caractères .NET Unicode UTF-16 (et inversement) !

Créer son propre wrapper de chaîne de caractères.

Il arrive cependant des situations ou vous devez programmer vous même votre propre wrapper (par exemple vous souhaitez envoyer des chaînes de caractères au format ASCII dans un socket).

Le .NET Framework propose pour cela une classe contenant 2 méthodes duales (présente dans l’espace de noms System.Text) :

  • Encoding.GetString() (Convertit un tableau d’octets en une chaine de caractère)
  • Encoding.GetBytes()  (Convertit un chaîne de caractère en un tableau d’octets).

Le jeu de caractères utilisé est l’instance Encoding que vous utilisez lors de l’appel de ces méthodes.

Microsoft propose dans le .NET Framework des instances d’Encoding souvent utilisées qui sont les suivantes :

  • Encoding.Ascii
  • Encoding.BigEndianUnicode
  • Encoding.Default (Codage ANSI Windows)
  • Encoding.Unicode (UTF-16)
  • Encoding.UTF32
  • Encoding.UTF7
  • Encoding.UTF8

Il existe encore d’autres jeux de caractères sous le .NET Framework, dont la liste est disponible en utilisant la méthode statique Encoding.GetEncodings() .

A vous de choisir le bon codage à utiliser pour récupérer ou écrire des chaînes de caractères .NET coder sous Unicode UTF-16 ! (Ou alors faites comme Microsoft, proposez une propriété dans vos wrappers afin de pouvoir choisir n’importe quel type de codage).

Pourquoi le code présent au début de l’article est-il incorrect ?

Tout simplement parce que vous convertissez une chaîne .NET Unicode UTF-16 en un jeu de caractère qui sera stocké dans « une réprésentation UTF-16″…
Bref, en utilisant une telle méthode, les autres développeurs vont croire que la chaîne convertie – dont ils ne savent peut-être pas qu’elle est convertie – est stocké en UTF-16, alors que ce n’est pas le cas !

Conclusion

J’espère que cet article vous a permis de bien comprendre le principe de gestion du codage des chaînes de caractères sous .NET.
Aussi, pensez absolument à bannir le code (et donc le concept) présent au début de l’article !

Gardez à l’esprit : System.String = Chaîne de caractère Unicode UTF-16 !