Comment obtenir une représentation byte cohérente des chaînes en C# sans spécifier manuellement un encodage?

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

je vais crypter la chaîne. Je peux le crypter sans conversion, mais j'aimerais savoir pourquoi l'encodage vient jouer ici.

en outre, pourquoi devrait-on tenir compte de l'encodage? Est-ce que je ne peux pas simplement obtenir les octets dans lesquels la chaîne a été stockée? Pourquoi est-il une dépendance sur les encodages de caractères?

1948
demandé sur Dragonthoughts 2009-01-23 16:39:54

30 réponses

Contrairement aux réponses données ici, vous N'avez pas à vous soucier d'encoder si les octets n'ont pas besoin d'être interprétés!

comme vous l'avez mentionné, votre but est simplement de " obtenir les octets dans lesquels la chaîne a été stockée " .

(Et, bien sûr, pour être en mesure de re-construire la chaîne d'octets.)

Pour ces objectifs, honnêtement, je ne pas comprendre pourquoi les gens continuent à vous dire que vous avez besoin des encodages. Vous n'avez certainement pas à vous soucier des encodages pour cela.

faites ceci à 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;
}

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) n'essayez pas d'interpréter les octets d'une façon ou d'une autre, ce que vous n'avez évidemment pas mentionné que vous avez l'intention de faire, alors il y a rien faux avec cette approche! Se soucier de l'encodage rend votre vie plus compliquée sans raison.

avantage Supplémentaire de cette approche:

cela n'a pas d'importance si la chaîne contient des caractères invalides, parce que vous pouvez toujours obtenir les données et reconstruire la chaîne originale de toute façon!

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

si vous avez utilisé un encodage, cependant, il vous aurait donné du mal à encoder/décoder des caractères invalides.

1731
répondu Mehrdad 2015-07-18 21:46:49

cela dépend du codage 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 échantillon pourquoi l'encodage des questions:

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 '?'

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

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

Voir l'Encodage des Caractères dans le .NET Framework (en anglais) pour plus d'informations.

1059
répondu bmotmans 2015-04-24 09:52:05

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'y êtes pas obligé...

250
répondu Erik A. Brandstadmoen 2015-07-23 14:32:52
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());
106
répondu Michael Buen 2009-01-26 06:29:52

vous devez tenir compte de l'encodage, parce que 1 caractère pourrait être représenté par 1 ou plus octets (jusqu'à environ 6), et des encodages différents traiteront ces octets différemment.

Joel a un message à ce sujet:

le Minimum absolu chaque développeur de logiciel doit absolument, positivement connaître Unicode et les jeux de caractères (pas D'Excuses!)

82
répondu Zhaph - Ben Duguid 2009-01-23 14:03:30

C'est une question populaire. Il est important de comprendre ce que l'auteur de la question demande, et qu'il est différent de ce qui est probablement le plus commun. Pour décourager le mauvais usage du code là où il n'est pas nécessaire, j'ai répondu plus tard en premier.

Besoin Commun

chaque chaîne possède un jeu de caractères et un encodage. Lorsque vous convertissez un System.String objet à un tableau de System.Byte vous avez encore un jeu de caractères et encodage. pour la plupart des usages, vous savez quel jeu de caractères et encodage vous avez besoin et .NET rend simple à "copier avec conversion." il suffit de choisir la classe appropriée Encoding .

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

la conversion peut être nécessaire pour gérer les cas où le jeu de caractères ou l'encodage cible ne supporte pas un caractère qui est dans la source. Vous avez le choix entre l'exception, la substitution ou le saut. La politique par défaut est de remplacer un '?'.

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

clairement, les conversions ne sont pas nécessairement sans perte!

Note: pour System.String , le jeu de caractères source est Unicode.

la seule chose qui prête à confusion est que .NET utilise le nom d'un jeu de caractères pour le nom d'un codage particulier de ce jeu de caractères. Encoding.Unicode doit être appelé Encoding.UTF16 .

C'est tout pour la plupart des usages. Si c'est ce dont tu as besoin, arrête de lire ici. plaisir Joel Spolsky l'article si vous ne comprenez pas ce qu'est un encodage.

Besoins Spécifiques

maintenant, l'auteur de la question demande, " chaque chaîne est stockée comme un tableau d'octets, Non? Pourquoi je ne peux pas avoir ces octets?"

il ne veut pas de conversion.

De la C# spec :

Le traitement des caractères et des chaînes de caractères dans C# utilise L'encodage Unicode. Ombles type représente une unité de code UTF-16, et le type de chaîne représente un séquence D'unités de code UTF-16.

ainsi, nous savons que si nous demandons la conversion nulle (i.e., de UTF-16 à UTF-16), nous obtiendrons le résultat désiré:

Encoding.Unicode.GetBytes(".NET String to byte array")

mais pour éviter la mention d'encodages, nous devons le faire d'une autre manière. Si un type de données intermédiaire est acceptable, il y a un raccourci conceptuel pour ceci:

".NET String to byte array".ToCharArray()

qui ne nous donne pas le type de données désiré mais la réponse de Mehrdad montre comment convertir ce tableau de caractères en un tableau de octets en utilisant BlockCopy . Cependant, cela copie la chaîne deux fois! Et, il utilise aussi explicitement le code spécifique à l'encodage: le type de données System.Char .

La seule façon d'obtenir pour les octets de la Chaîne est stockée en est d'utiliser un pointeur. L'instruction fixed permet de prendre l'adresse des valeurs. Du C # spec:

[pour] une expression de type string, ... l'initialiseur calcule le l'adresse du premier caractère dans la chaîne.

pour ce faire, le compilateur écrit du code skip sur les autres parties de l'objet string avec RuntimeHelpers.OffsetToStringData . Donc, pour obtenir les premières octets, il suffit de créer un pointeur vers la chaîne et copie le nombre d'octets nécessaires.

// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 codeunits 
       and such codeunits are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

comme @CodesInChaos l'a souligné, le résultat dépend de l'encanéité de la machine. Mais l'auteur de la question ne s'en préoccupe pas.

77
répondu Tom Blodget 2017-05-23 10:31:37

juste pour démontrer que le son de Mehrdrad answer fonctionne, son approche peut même persister les caractères de substitution non appariés (dont beaucoup avaient nivelé contre ma réponse, mais dont tout le monde est également coupable, par exemple System.Text.Encoding.UTF8.GetBytes , System.Text.Encoding.Unicode.GetBytes ; ces méthodes d'encodage ne peuvent pas persister les caractères de substitution élevés d800 par exemple, et ceux qui remplacent simplement les caractères de substitution élevés avec valeur 151950920" ) :

using System;

class Program
{     
    static void Main(string[] args)
    {
        string t = "爱虫";            
        string s = "Test\ud800Test"; 

        byte[] dumpToBytes = GetBytes(s);
        string getItBack = GetString(dumpToBytes);

        foreach (char item in getItBack)
        {
            Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
        }    
    }

    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;
    }

    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);
    }        
}

sortie:

T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74

essayez ça avec le système .Texte.Encodage.UTF8.Système GetBytes ou .Texte.Encodage.Unicode.GetBytes , ils remplaceront simplement les caractères de substitution élevés avec la valeur fffd

chaque fois qu'il y a un mouvement dans cette question, je pense toujours à un serializer(que ce soit de Microsoft ou d'un composant tiers) qui peut persister chaînes même si elle contient des caractères de substitution non appariés; Je google cela de temps en temps: sérialisation caractère de substitution non apparié .net . Cela ne me fait pas perdre le sommeil, mais c'est un peu ennuyeux quand de temps en temps il y a quelqu'un qui commente ma réponse que c'est imparfait, mais leurs réponses sont tout aussi imparfaites quand il s'agit de personnages de substitution non appariés.

Zut, Microsoft aurait dû juste utiliser System.Buffer.BlockCopy dans son BinaryFormatter Kong

37
répondu Michael Buen 2017-05-23 12:18:28

Essayez ceci, beaucoup moins de code:

System.Text.Encoding.UTF8.GetBytes("TEST String");
36
répondu Nathan 2015-04-24 09:58:10

la première partie de votre question (Comment obtenir les octets) a déjà été répondue par d'autres: regardez dans l'espace de noms System.Text.Encoding .

je vais répondre à votre question: pourquoi avez-vous besoin de choisir un encodage? Pourquoi ne peux-tu pas l'obtenir de la classe string elle-même?

, La réponse est en deux parties.

tout D'abord , les octets utilisés en interne par la classe de chaîne de caractères n'ont pas d'importance , et chaque fois que vous supposons qu'ils le fassent vous introduisez probablement un bug.

si votre programme est entièrement dans le monde.Net, alors vous n'avez pas besoin de vous soucier d'obtenir des tableaux byte pour les chaînes, même si vous envoyez des données à travers un réseau. Utilisez plutôt la sérialisation .Net pour vous soucier de la transmission des données. Vous ne vous inquiétez plus des octets actuels: le formatteur de sérialisation le fait pour vous.

d'un autre côté, que faire si vous envoyez ces octets quelque part que vous ne pouvez pas garantir va tirer des données d'un flux .net sérialisé? Dans ce cas, vous avez certainement besoin de se soucier de l'encodage, parce que évidemment ce système externe se soucie. Donc, encore une fois, les octets internes utilisés par la chaîne n'ont pas d'importance: vous devez choisir un encodage pour que vous puissiez être explicite sur cet encodage du côté de réception, même si c'est le même encodage utilisé en interne par .Net.

je comprends que, dans ce cas, vous pourriez préférer utiliser le les octets stockés par la variable string en mémoire lorsque c'est possible, avec l'idée qu'il pourrait sauver du travail en créant votre flux octet. Cependant, je vous le dis, il est tout simplement pas important par rapport à s'assurer que votre sortie est comprise à l'autre extrémité, et de garantir que vous doit être explicite avec votre encodage. En outre, si vous voulez vraiment faire correspondre vos octets internes, vous pouvez déjà simplement choisir l'encodage Unicode , et obtenir ces économies de performance.

ce Qui m'amène à la deuxième partie... choisir le Unicode encodage est dire à .Net d'utiliser les octets sous-jacents. Vous devez choisir cet encodage, parce que lorsqu'un nouveau Unicode-Plus fanglé sort, L'exécution .Net doit être libre d'utiliser ce nouveau, meilleur modèle d'encodage sans casser votre programme. Mais, pour le moment (et pour l'avenir prévisible), il suffit de choisir L'encodage Unicode vous donne ce que vous vouloir.

il est également important de comprendre que votre chaîne de caractères doit être réécrite en fil de fer, ce qui implique au moins une traduction du motif en bits , même si vous utilisez un encodage correspondant . L'ordinateur doit tenir compte de choses comme Big vs Little Endian, network byte order, packetization, session information, etc.

36
répondu Joel Coehoorn 2017-09-25 21:13:44

Eh bien, j'ai lu toutes les réponses et elles portaient sur l'utilisation de l'encodage ou sur la sérialisation qui laisse tomber les substituts non appariés.

c'est mauvais quand la chaîne, par exemple, vient de SQL Server où elle a été construite à partir d'un tableau d'octets stockant, par exemple, un hachage de mot de passe. Si nous en laissons tomber quelque chose, il stockera un hash invalide, et si nous voulons le stocker en XML, nous voulons le laisser intact (parce que L'auteur XML laisse tomber une exception sur n'importe quel une mère porteuse non porteuse qu'il trouve).

donc j'utilise Base64 encodage de tableaux d'octets dans de tels cas, mais bon, sur Internet il n'y a qu'une solution à cela dans C#, et il y a un bug dedans et c'est seulement une façon, donc j'ai corrigé le bug et la procédure de retour écrit. Vous voilà, futurs googleurs:

public static byte[] StringToBytes(string str)
{
    byte[] data = new byte[str.Length * 2];
    for (int i = 0; i < str.Length; ++i)
    {
        char ch = str[i];
        data[i * 2] = (byte)(ch & 0xFF);
        data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
    }

    return data;
}

public static string StringFromBytes(byte[] arr)
{
    char[] ch = new char[arr.Length / 2];
    for (int i = 0; i < ch.Length; ++i)
    {
        ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
    }
    return new String(ch);
}
22
répondu Gman 2017-03-09 08:55:32

veuillez également expliquer pourquoi le codage devrait être pris en considération. Est-ce que je ne peux pas simplement obtenir les octets dans lesquels la chaîne a été stockée? Pourquoi cette dépendance à l'encodage?!!!

parce qu'il n'y a pas"les octets de la chaîne".

une chaîne de caractères (ou plus généralement un texte) est composée de caractères: lettres, chiffres et autres symboles. C'est tout. Les ordinateurs, cependant, ne savent rien sur les caractères; ils ne peuvent traiter que les octets. Par conséquent, si vous voulez stocker ou transmettre du texte en utilisant un ordinateur, vous devez transformer les caractères en octets. Comment faites-vous cela? C'est là que les codages arrivent sur la scène.

un encodage n'est rien d'autre qu'une convention pour traduire des caractères logiques en octets physiques. Le codage le plus simple et le plus connu est ASCII, et il est tout ce dont vous avez besoin si vous écrivez en anglais. Pour les autres langues, vous aurez besoin d'encodages plus complets, étant N'importe quel Unicode est le choix le plus sûr de nos jours.

donc, en résumé, essayer de" récupérer les octets d'une chaîne sans utiliser d'encodage "est aussi impossible que"Écrire un texte sans utiliser aucune langue".

soit dit en passant, je vous recommande fortement (et à quiconque, d'ailleurs) de lire ce petit morceau de sagesse: le Minimum absolu chaque développeur de logiciel absolument, positivement doit savoir sur Unicode et les jeux de caractères (pas D'Excuses!)

19
répondu Konamiman 2015-10-23 06:19:47

C# pour convertir un string en un byte tableau:

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}
18
répondu Shyam sundar shah 2016-08-12 18:39:11
byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}
16
répondu gkrogers 2009-01-23 13:43:18

vous pouvez utiliser le code suivant pour la conversion entre la chaîne et le tableau d'octets.

string s = "Hello World";

// String to Byte[]

byte[] byte1 = System.Text.Encoding.Default.GetBytes(s);

// OR

byte[] byte2 = System.Text.ASCIIEncoding.Default.GetBytes(s);

// Byte[] to string

string str = System.Text.Encoding.UTF8.GetString(byte1);
15
répondu Jarvis Stark 2014-09-09 11:30:51

Je ne suis pas sûr, mais je pense que la chaîne stocke son information comme un tableau de caractères, qui est inefficace avec des octets. Plus précisément, la définition D'un car Est "représente un caractère Unicode".

prendre cet exemple d'échantillon:

String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info =  Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
    System.Console.WriteLine(enc.Name + " - " 
      + enc.GetEncoding().GetByteCount(str)
      + enc.GetEncoding().GetByteCount(str2));
}

notez que la réponse Unicode est de 14 octets dans les deux cas, alors que la réponse UTF-8 n'est que de 9 octets pour la première et de 7 octets pour la seconde.

Donc, si vous voulez juste les octets utilisé par la chaîne, il suffit d'utiliser Encoding.Unicode , mais il sera inefficace avec un espace de stockage.

11
répondu Ed Marty 2016-08-12 18:38:55

la question clé est qu'un glyphe dans une chaîne prend 32 bits (16 bits pour un code de caractère) mais un octet a seulement 8 bits à épargner. Il n'y a pas de mapping un-à-un sauf si vous vous limitez à des chaînes qui ne contiennent que des caractères ASCII. Système.Texte.Encodage a beaucoup de façons de mapper une chaîne de caractères à byte[], vous devez choisir un qui évite la perte d'information et qui est facile à utiliser par votre client quand elle a besoin de mapper le byte[] retour à une chaîne de caractères.

Utf8 est un encodage populaire, il est compact et pas lossy.

9
répondu Hans Passant 2009-01-23 14:15:26

voie la plus rapide

public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

MODIFIER comme Makotosan commenté c'est maintenant la meilleure façon:

Encoding.UTF8.GetBytes(text)
8
répondu Sunrising 2016-08-04 10:31:17

utiliser:

    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

le résultat est:

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103
7
répondu mashet 2017-01-09 01:22:07

vous pouvez utiliser le code suivant pour convertir un string en un byte array dans .NET

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);
5
répondu Shyam sundar shah 2014-05-02 07:39:30

L'approche la plus proche de la question de L'OP est celle de Tom Blodget, qui entre dans l'objet et extrait les octets. Je dis proche parce que cela dépend de l'implémentation de L'objet String.

"Can't I simply get what bytes the string has been stored in?"

bien sûr, mais c'est là que l'erreur fondamentale dans la question se pose. La chaîne est un objet qui pourrait avoir une structure de données intéressante. Nous le savons déjà, car cela permet de stocker des substituts non appariés. Il pourrait stocker la longueur. Il pourrait garder un pointeur à chacun des substituts "appariés" permettant un comptage rapide. Etc. Tous ces octets supplémentaires ne font pas partie des données de caractère.

ce que vous voulez est les octets de chaque caractère dans un tableau. Et c'est là que "encodage". Par défaut, vous obtiendrez UTF-16LE. Si vous ne vous souciez pas des octets eux-mêmes sauf pour le voyage aller-retour, alors vous pouvez choisir n'importe quel encodage, y compris le 'défaut', et le convertir plus tard (en supposant les mêmes paramètres tels que comme ce qu'était l'encodage par défaut, les points de code, les corrections de bug, les choses permises telles que les substituts non appariés, etc.

mais pourquoi laisser le "codage" à la magie? Pourquoi ne pas spécifier l'encodage pour que vous sachiez quels octets vous allez obtenir?

"Why is there a dependency on character encodings?"

encodage (dans ce contexte) signifie simplement les octets qui représentent votre chaîne. Pas les octets de l'objet string. Vous vouliez les octets dans lesquels la chaîne a été stockée -- c'est là que la question était demanda naïvement. Vous vouliez les octets de chaîne dans un tableau contigu qui représente la chaîne, et pas toutes les autres données binaires qu'un objet string peut contenir.

ce qui signifie que la façon dont une chaîne est stockée n'est pas pertinente. Vous voulez une chaîne "Codé" en octets dans un tableau d'octets.

j'aime la réponse de Tom Bloget parce qu'il vous a pris vers les "bytes of the string object" direction. Il est dépendant de la mise en œuvre, cependant, et parce qu'il regarde à internes, il peut être difficile de reconstituer une copie de la chaîne.

la réponse de Mehrdad est erronée parce qu'elle est trompeuse au niveau conceptuel. Vous avez encore une liste d'octets codés. Sa solution particulière permet de préserver les substituts non appariés -- cela dépend de la mise en œuvre. Sa solution particulière ne produirait pas les octets de la chaîne avec précision si GetBytes renvoyait la chaîne en UTF-8 par défaut.


j'ai changé d'avis à ce sujet (la solution de Mehrdad) -- ce n'est pas obtenir les octets de la chaîne, mais plutôt les octets du tableau de caractères qui a été créé à partir de la chaîne. Indépendamment de l'encodage, le type de données char en c# est une taille fixe. Cela permet de produire un tableau d'octets de longueur uniforme et de reproduire le tableau de caractères en fonction de la taille du tableau d'octets. Donc si L'encodage était UTF-8, mais chaque caractère était de 6 octets pour accommoder le la plus grande valeur utf8, ça marcherait toujours. Donc en effet -- codage des caractères n'a pas d'importance.

mais une conversion a été utilisée -- chaque caractère a été placé dans une boîte de taille fixe (Type de caractère c#). Toutefois, cette représentation n'a pas d'importance, ce qui est techniquement la réponse au PO. Donc ... si tu dois te convertir de toute façon... Pourquoi pas "coder'?

4
répondu Gerard ONeill 2017-11-01 19:44:31

avec l'avènement de Span<T> sorti avec C# 7.2, la technique canonique pour capturer la représentation mémoire sous-jacente d'une chaîne dans un tableau byte géré est:

byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

la reconvertir devrait être un non-starter parce que cela signifie que vous interprétez les données d'une manière ou d'une autre, mais par souci d'exhaustivité:

string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

les noms NonPortableCast et DangerousGetPinnableReference devraient argument que tu ne devrais probablement pas faire ça.

notez que travailler avec Span<T> nécessite l'installation du système .Paquet noget mémoire .

quoi qu'il en soit, la actuelle la question initiale et les commentaires de suivi laissent entendre que la mémoire sous-jacente n'est pas" interprétée " (ce qui, je suppose, signifie n'est pas modifié ou lu au-delà de la nécessité de l'écrire tel quel), indiquant qu'une certaine implémentation de la classe Stream devrait être utilisée au lieu de raisonner sur les données en tant que chaînes.

4
répondu John Rasch 2018-01-10 20:21:12

voici ma mise en œuvre dangereuse de String en Byte[] conversion:

public static unsafe Byte[] GetBytes(String s)
{
    Int32 length = s.Length * sizeof(Char);
    Byte[] bytes = new Byte[length];

    fixed (Char* pInput = s)
    fixed (Byte* pBytes = bytes)
    {
        Byte* source = (Byte*)pInput;
        Byte* destination = pBytes;

        if (length >= 16)
        {
            do
            {
                *((Int64*)destination) = *((Int64*)source);
                *((Int64*)(destination + 8)) = *((Int64*)(source + 8));

                source += 16;
                destination += 16;
            }
            while ((length -= 16) >= 16);
        }

        if (length > 0)
        {
            if ((length & 8) != 0)
            {
                *((Int64*)destination) = *((Int64*)source);

                source += 8;
                destination += 8;
            }

            if ((length & 4) != 0)
            {
                *((Int32*)destination) = *((Int32*)source);

                source += 4;
                destination += 4;
            }

            if ((length & 2) != 0)
            {
                *((Int16*)destination) = *((Int16*)source);

                source += 2;
                destination += 2;
            }

            if ((length & 1) != 0)
            {
                ++source;
                ++destination;

                destination[0] = source[0];
            }
        }
    }

    return bytes;
}

c'est beaucoup plus rapide que celui de l'anwser accepté, même si pas aussi élégant qu'il est. Voici mes repères de chronomètre plus de 10000000 itérations:

[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms

[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms

[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms

pour l'utiliser, vous devez cocher" Autoriser le code dangereux " dans vos propriétés de construction de projet. Comme pour .net Framework 3.5, cette méthode peut également être utilisée comme extension de chaîne:

public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}
3
répondu Tommaso Belluzzo 2016-08-12 18:38:24

deux voies:

public static byte[] StrToByteArray(this string s)
{
    List<byte> value = new List<byte>();
    foreach (char c in s.ToCharArray())
        value.Add(c.ToByte());
    return value.ToArray();
}

et,

public static byte[] StrToByteArray(this string s)
{
    s = s.Replace(" ", string.Empty);
    byte[] buffer = new byte[s.Length / 2];
    for (int i = 0; i < s.Length; i += 2)
        buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
    return buffer;
}

j'ai tendance à utiliser le bas plus souvent que le haut, Je ne les ai pas référencés pour la vitesse.

2
répondu 2009-02-19 21:03:34
bytes[] buffer = UnicodeEncoding.UTF8.GetBytes(string something); //for converting to UTF then get its bytes

bytes[] buffer = ASCIIEncoding.ASCII.GetBytes(string something); //for converting to ascii then get its bytes
2
répondu user1120193 2012-01-02 11:07:00

code simple avec LINQ

string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();

EDIT : comme indiqué ci-dessous, il n'est pas un bon moyen.

mais vous pouvez encore l'utiliser pour comprendre LINQ avec un codage plus approprié:

string s = "abc"
byte[] b = s.Cast<byte>().ToArray();
2
répondu Avlin 2013-12-18 10:13:26

Si vous voulez vraiment une copie de la sous-octets d'une chaîne de caractères, vous pouvez utiliser une fonction comme celle qui suit. cependant, vous ne devriez pas s'il vous plaît lire la suite pour savoir pourquoi.

[DllImport(
        "msvcrt.dll",
        EntryPoint = "memcpy",
        CallingConvention = CallingConvention.Cdecl,
        SetLastError = false)]
private static extern unsafe void* UnsafeMemoryCopy(
    void* destination,
    void* source,
    uint count);

public static byte[] GetUnderlyingBytes(string source)
{
    var length = source.Length * sizeof(char);
    var result = new byte[length];
    unsafe
    {
        fixed (char* firstSourceChar = source)
        fixed (byte* firstDestination = result)
        {
            var firstSource = (byte*)firstSourceChar;
            UnsafeMemoryCopy(
                firstDestination,
                firstSource,
                (uint)length);
        }
    }

    return result;
}

cette fonction vous obtiendra une copie des octets sous-jacents à votre chaîne, assez rapidement. Vous obtiendrez ces octets de n'importe quelle façon qu'ils encodent sur votre système. Ce codage est presque certainement UTF-16LE, mais c'est un détail d'implémentation que vous ne devriez pas avoir à s'inquiéter.

Il serait plus sûr, plus simple et plus fiable ,

System.Text.Encoding.Unicode.GetBytes()

selon toute probabilité cela donnera le même résultat, est plus facile à taper, et les octets seront toujours aller-retour avec un appel à

System.Text.Encoding.Unicode.GetString()
2
répondu Jodrell 2014-11-25 10:29:12

utilisez simplement ceci:

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
2
répondu alireza amini 2015-07-01 01:14:44

comment convertir une chaîne en octet[] dans .NET (C#) sans spécifier manuellement un encodage spécifique?

Un chaîne .NET représente le texte comme une séquence de code UTF-16 unités, de sorte que les octets sont encodées en mémoire en UTF-16 déjà.

réponse de Mehrdad

Vous pouvez utiliser Mehrdad la réponse de , mais il ne en fait, utilisez un encodage car les caractères sont UTF-16. Il appelle ToCharArray qui en regardant la source crée un char[] et copie la mémoire à lui directement. Puis il copie les données dans un tableau d'octets qui est également attribuée. Ainsi, sous le capot, il copie les octets sous-jacents deux fois et attribue un tableau de caractères qui n'est pas utilisé après l'appel.

Tom Blodget la Réponse de

la réponse de Tom Blodget est de 20-30% plus rapide que Mehrdad car il saute l'étape intermédiaire de l'allocation d'un tableau de caractères et de la copie des octets à lui, mais il nécessite que vous compilez avec l'option /unsafe . Si vous ne voulez absolument pas utiliser l'encodage, je pense que c'est la voie à suivre. Si vous mettez votre login de cryptage dans le bloc fixed , vous n'avez même pas besoin d'allouer un tableau d'octets séparé et de copier les octets vers lui.

en outre, pourquoi devrait-on tenir compte de l'encodage? Est-ce que je ne peux pas simplement obtenir les octets dans lesquels la chaîne a été stockée? Pourquoi est-il une dépendance sur les encodages de caractères?

Parce que c'est la bonne façon de le faire. string est une abstraction.

L'utilisation d'un encodage pourrait vous causer des problèmes si vous avez des 'chaînes' avec des caractères invalides, mais cela ne devrait pas se produire. Si vous introduisez des données dans votre chaîne avec invalide personnages vous le faites mal. Vous devriez probablement utiliser un tableau byte ou un encodage Base64 pour commencer.

Si vous utilisez System.Text.Encoding.Unicode , votre code sera plus résistant. Vous n'avez pas à vous soucier du endianness du système sur lequel votre code sera exécuté. Vous n'avez pas à vous inquiéter si la prochaine version du CLR utilisera un codage de caractères interne différent.

je pense que la question n'est pas pourquoi vous voulez inquiète-toi de l'encodage, mais pourquoi tu veux l'ignorer et utiliser autre chose. L'encodage est censé représenter l'abstraction d'une chaîne dans une séquence d'octets. System.Text.Encoding.Unicode vous donnera un petit encodage d'ordre de octet endian et effectuera la même chose sur chaque système, maintenant et dans le futur.

2
répondu Jason Goemaat 2018-07-02 20:51:49

la chaîne de caractères peut être convertie en tableau octet de différentes façons, en raison du fait suivant: .NET supporte Unicode, et Unicode standardise plusieurs encodages de différence appelés UTFs. Ils ont différentes longueurs de la représentation byte mais sont équivalents dans ce sens que lorsqu'une chaîne est encodée, elle peut être codée à nouveau à la chaîne, mais si la chaîne est encodée avec un UTF et décodé dans l'hypothèse D'un UTF différent si peut être vissé vers le haut.

Also, .NET supporte les encodages non Unicode, mais ils ne sont pas valides dans le cas général (seront valides seulement si un sous-ensemble limité de point de code Unicode est utilisé dans une chaîne de caractères réelle, telle que ASCII). À L'interne, .NET supporte UTF-16, mais pour la représentation stream, UTF-8 est habituellement utilisé. Il s'agit également d'une norme de facto pour L'Internet.

sans surprise, la sérialisation de la chaîne dans un tableau d'octets et la desérialisation est soutenue par la classe System.Text.Encoding , qui est une classe abstraite; son les classes dérivées supportent les codages en béton: ASCIIEncoding et quatre UTFs ( System.Text.UnicodeEncoding supporte UTF-16)

Ref ce lien.

pour la sérialisation à un tableau d'octets en utilisant System.Text.Encoding.GetBytes . Pour le fonctionnement inverse, utiliser System.Text.Encoding.GetChars . Cette fonction renvoie un tableau de caractères, donc pour obtenir une chaîne de caractères, utilisez un constructeur de chaînes de caractères System.String(char[]) .

Ref cette page.

exemple:

string myString = //... some string

System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);

//next lines are written in response to a follow-up questions:

myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);

//how many times shall I repeat it to show there is a round-trip? :-)
1
répondu Vijay Singh Rana 2017-08-17 07:33:04

de byte[] à string :

        return BitConverter.ToString(bytes);
0
répondu Piero Alberto 2017-01-09 01:19:24