2352 votes

Comment obtenir une représentation cohérente en octets des chaînes de caractères en C# sans spécifier manuellement un encodage ?

Comment convertir un string à un byte[] dans .NET (C#) sans spécifier manuellement un encodage spécifique ?

Je vais crypter la chaîne. Je peux la chiffrer sans la convertir, mais j'aimerais quand même savoir pourquoi l'encodage entre en jeu ici.

En outre, pourquoi l'encodage devrait-il être pris en considération ? Ne puis-je pas simplement obtenir les octets dans lesquels la chaîne a été stockée ? Pourquoi y a-t-il une dépendance aux encodages de caractères ?

2 votes

Votre confusion sur le rôle de l'encodage me fait me demander si c'est la bonne question. Pourquoi essayez-vous de convertir une chaîne de caractères en un tableau d'octets ? Qu'allez-vous faire avec le tableau d'octets ?

0 votes

Je vais le crypter. Je peux le crypter sans le convertir, mais j'aimerais quand même savoir pourquoi le codage entre en jeu ici. Donnez-moi juste les octets, c'est ce que je dis.

6 votes

Si vous le cryptez, vous devrez toujours connaître le codage après le décryptage afin de savoir comment réinterpréter ces octets en une chaîne de caractères.

1940voto

Mehrdad Points 70493

Contrairement aux réponses données ici, vous n'avez pas besoin de vous soucier de l'encodage. _si_ les octets n'ont pas besoin d'être interprétés !

Comme vous l'avez mentionné, votre but est, simplement, de "récupérer les octets dans lesquels la chaîne a été stockée" .
(Et, bien sûr, être capable de reconstruire la chaîne de caractères à partir des octets).

Pour ces objectifs, je fais honnêtement no comprendre pourquoi les gens ne cessent de vous dire que vous avez besoin des encodages. Vous n'avez certainement PAS besoin de vous soucier des encodages pour cela.

Fais ça à la place :

static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

// Do NOT use on arbitrary bytes; only use on GetBytes's output on the SAME system
static string GetString(byte[] bytes)
{
    char[] chars = new char[bytes.Length / sizeof(char)];
    System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    return new string(chars);
}

Tant que votre programme (ou d'autres programmes) ne tente pas de interpréter les octets d'une manière ou d'une autre, ce que vous n'avez manifestement pas mentionné avoir l'intention de faire, il y a alors rien Cette approche n'est pas mauvaise ! Se préoccuper des codages ne fait que vous compliquer la vie sans raison réelle.

Avantage supplémentaire de cette approche : Peu importe que la chaîne contienne des caractères invalides, car vous pouvez toujours récupérer les données et reconstruire la chaîne d'origine !

Il sera codé et décodé de la même façon, parce que vous êtes juste en regardant les octets .

Mais si vous aviez utilisé un encodage spécifique, vous auriez eu des problèmes avec l'encodage/décodage de caractères invalides.

5 votes

+1 Exactement ce que je pense, je ne comprends pas l'insistance de certains ici sur l'encodage. Il suffit de faire un vidage de mémoire / sérialisation (la bibliothèque de sérialisation par défaut de Microsoft a des défauts cependant). J'espère que je connais cette API BlockCopy avant :-)

3 votes

@MichaelBuen : Ouaip. Aussi longtemps que vos vidages de mémoire/sérialisations font no essayer d'interpréter les données, c'est très bien. La règle générale à retenir est la suivante : Si votre programme (ou un autre programme) a besoin de convertir la sortie de GetBytes à la même chaîne, il peut sólo utiliser GetString pour ce faire. Tant que vous n'enfreignez pas cette règle, vous pouvez ignorer complètement le concept de codage.

0 votes

@Mehrdad Je suis d'accord avec votre logique, mais j'ai été surpris lorsque je l'ai testé que la méthode d'encodage soit légèrement plus rapide. Je suppose que je m'attendais à ce que votre méthode soit plus rapide (il n'y a pas grand chose dedans cependant).

1142voto

bmotmans Points 6788

Cela dépend de l'encodage de votre chaîne ( ASCII , UTF-8 , ...).

Par exemple :

byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

Un petit exemple de l'importance du codage :

string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);

Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'

L'ASCII n'est tout simplement pas équipé pour traiter les caractères spéciaux.

En interne, le cadre .NET utilise UTF-16 pour représenter les chaînes de caractères, donc si vous voulez simplement obtenir les octets exacts que .NET utilise, utilisez System.Text.Encoding.Unicode.GetBytes (...) .

Voir Codage des caractères dans le cadre de .NET (MSDN) pour plus d'informations.

16 votes

Mais, pourquoi faut-il prendre en compte l'encodage ? Pourquoi ne puis-je pas simplement obtenir les octets sans avoir à voir quel encodage est utilisé ? Même si cela était nécessaire, l'objet String lui-même ne devrait-il pas savoir quel encodage est utilisé et simplement vider ce qui est en mémoire ?

66 votes

Les chaînes de caractères .NET sont toujours codées en Unicode. Utilisez donc System.Text.Encoding.Unicode.GetBytes() ; pour obtenir le jeu d'octets que .NET utilise pour représenter les caractères. Mais pourquoi voulez-vous cela ? Je recommande UTF-8, en particulier lorsque la plupart des caractères sont dans le jeu latin occidental.

1 votes

Il y a aussi System.Text.Encoding.Default.

304voto

La réponse acceptée est très, très compliquée. Utilisez les classes .NET incluses pour cela :

const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

Ne réinventez pas la roue si vous n'avez pas à le faire...

17 votes

Au cas où la réponse acceptée serait modifiée, à des fins d'enregistrement, il s'agit de la réponse de Mehrdad à l'heure et à la date actuelles. Espérons que le PO reviendra sur cette question et acceptera une meilleure solution.

9 votes

Bon en principe mais, l'encodage devrait être System.Text.Encoding.Unicode pour être équivalent à la réponse de Mehrdad.

7 votes

La question a été modifiée un million de fois depuis la réponse originale, donc ma réponse est peut-être un peu dépassée. Je n'ai jamais eu l'intention de donner un équivalent exace à la réponse de Mehrdad, mais de donner une manière raisonnable de le faire. Mais, vous avez peut-être raison. Cependant, la phrase "get what bytes the string has been stored in" dans la question originale est très imprécise. Stockée, où ? En mémoire ? Sur le disque ? Si en mémoire, System.Text.Encoding.Unicode.GetBytes serait probablement plus précis.

121voto

Michael Buen Points 20453
BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();

string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();

MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());

MessageBox.Show("Original string Length: " + orig.Length.ToString());

for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt

BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();            
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);

MessageBox.Show("Still intact :" + sx);

MessageBox.Show("Deserialize string Length(still intact): " 
    + sx.Length.ToString());

BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();

MessageBox.Show("Deserialize bytes Length(still intact): " 
   + bytesy.Length.ToString());

2 votes

Vous pouvez utiliser la même instance de BinaryFormatter pour toutes ces opérations.

3 votes

Très intéressant. Apparemment, il laisse tomber tout caractère Unicode de substitution élevé. Voir la documentation sur [[Formateur binaire](http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter%28v=VS.100%29.aspx) ]

100voto

Zhaph - Ben Duguid Points 18573

Vous devez tenir compte de l'encodage, car 1 caractère peut être représenté par 1 ou plus (jusqu'à environ 6), et les différents codages traiteront ces octets différemment.

Joel a publié un article à ce sujet :

Le minimum absolu que tout développeur de logiciels doit absolument, positivement connaître sur Unicode et les jeux de caractères (pas d'excuses !)

7 votes

"Un caractère peut être représenté par 1 ou plusieurs octets" Je suis d'accord. Je veux juste ces octets, quel que soit l'encodage de la chaîne. La seule façon dont une chaîne peut être stockée en mémoire est en octets. Même les caractères sont stockés comme 1 ou plusieurs octets. Je veux simplement mettre la main sur ces octets.

17 votes

Vous n'avez pas besoin des encodages à moins que vous (ou quelqu'un d'autre) n'ayez l'intention de interpréter les données, au lieu de les traiter comme un "bloc d'octets" générique. Pour des choses comme la compression, le cryptage, etc., il est inutile de se préoccuper de l'encodage. Voir ma réponse pour trouver un moyen de le faire sans se soucier de l'encodage.

10 votes

@Mehrdad - Tout à fait, mais la question initiale, telle qu'elle a été formulée dans ma réponse initiale, ne précisait pas ce que le PO allait faire de ces octets après les avoir convertis, et pour les futurs chercheurs, les informations à ce sujet sont pertinentes. Réponse de Joel et comme vous l'indiquez dans votre réponse : si vous restez dans le monde .NET et que vous utilisez vos méthodes pour convertir vers/depuis, vous êtes satisfait. Dès que vous sortez de ce cadre, l'encodage devient important.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X