wake-up-neo.com

Wie erhalte ich eine konsistente Bytedarstellung von Zeichenfolgen in C #, ohne manuell eine Codierung anzugeben?

Wie konvertiere ich ein string in ein byte[] in .NET (C #), ohne manuell eine bestimmte Codierung anzugeben?

Ich werde den String verschlüsseln. Ich kann es verschlüsseln, ohne es zu konvertieren, aber ich möchte immer noch wissen, warum das Codieren hier zum Einsatz kommt.

Warum sollte auch die Codierung berücksichtigt werden? Kann ich nicht einfach herausfinden, in welchen Bytes der String gespeichert wurde? Warum besteht eine Abhängigkeit von Zeichenkodierungen?

2088
Agnel Kurian

Im Gegensatz zu den hier gegebenen Antworten brauchen Sie sich KEINE Gedanken über die Codierung zu machen. , wenn die Bytes nicht interpretiert werden müssen!

Wie Sie bereits erwähnt haben, besteht Ihr Ziel einfach darin, "zu ermitteln, in welchen Bytes die Zeichenfolge gespeichert wurde" .
(Und natürlich, um den String aus den Bytes rekonstruieren zu können.)

Für diese Ziele verstehe ich ehrlich gesagt nicht , warum die Leute Ihnen immer wieder sagen, dass Sie die Kodierungen benötigen. Sie brauchen sich sicherlich KEINE Gedanken über Kodierungen zu machen.

Mach das einfach stattdessen:

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

Solange Ihr Programm (oder andere Programme) nicht versucht die Bytes zu interpretieren , was Sie offensichtlich nicht erwähnt haben, was Sie vorhaben, dann gibt es nichts falsch mit diesem Ansatz! Die Sorge um Kodierungen macht Ihr Leben nur ohne wirklichen Grund komplizierter.

Zusätzlicher Vorteil dieses Ansatzes:

Es spielt keine Rolle, ob die Zeichenfolge ungültige Zeichen enthält, da Sie die Daten trotzdem abrufen und die ursprüngliche Zeichenfolge wiederherstellen können!

Es wird genauso codiert und decodiert, da Sie nur die Bytes betrachten.

Wenn Sie jedoch eine bestimmte Kodierung verwendet hätten, hätten Sie Probleme beim Kodieren/Dekodieren ungültiger Zeichen.

1803
Mehrdad

Dies hängt von der Kodierung Ihres Strings ab ( ASCII , TF-8 , ...).

Zum Beispiel:

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

Ein kleines Beispiel, warum Codierung wichtig ist:

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 ist einfach nicht für den Umgang mit Sonderzeichen gerüstet.

Intern verwendet das .NET-Framework TF-16 , um Zeichenfolgen darzustellen. Wenn Sie also nur die genauen von .NET verwendeten Bytes abrufen möchten, verwenden Sie System.Text.Encoding.Unicode.GetBytes (...).

Weitere Informationen finden Sie unter Zeichencodierung in .NET Framework (MSDN).

1087
bmotmans

Die akzeptierte Antwort ist sehr, sehr kompliziert. Verwenden Sie dazu die mitgelieferten .NET-Klassen:

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

Erfinden Sie das Rad nicht neu, wenn Sie nicht müssen ...

273
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());
110
Michael Buen

Sie müssen die Codierung berücksichtigen, da 1 Zeichen durch 1 oder mehr Bytes (bis zu ca. 6) dargestellt werden kann und verschiedene Codierungen behandelt werden diese Bytes unterschiedlich.

Joel hat ein Posting dazu:

Das absolute Minimum, das jeder Softwareentwickler unbedingt unbedingt über Unicode und Zeichensätze wissen muss (keine Ausreden!)

91

Dies ist eine beliebte Frage. Es ist wichtig zu verstehen, was der Fragesteller fragt und was nicht das wahrscheinlich häufigste Bedürfnis ist. Um den Missbrauch des Codes zu verhindern, wenn er nicht benötigt wird, habe ich den späteren zuerst beantwortet.

Gemeinsames Bedürfnis

Jeder String hat einen Zeichensatz und eine Kodierung. Wenn Sie ein System.String -Objekt in ein Array von System.Byte konvertieren, verfügen Sie weiterhin über einen Zeichensatz und eine Codierung. Für die meisten Verwendungszwecke wissen Sie, welchen Zeichensatz und welche Codierung Sie benötigen, und .NET vereinfacht das "Kopieren mit Konvertierung". Wählen Sie einfach die entsprechende aus Encoding Klasse.

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

Die Konvertierung muss möglicherweise Fälle behandeln, in denen der Zielzeichensatz oder die Zielcodierung kein Zeichen in der Quelle unterstützt. Sie haben einige Möglichkeiten: Ausnahme, Ersetzung oder Überspringen. Standardmäßig wird ein '?'.

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

Conversions sind natürlich nicht unbedingt verlustfrei!

Hinweis: Für System.String ist der Quellzeichensatz Unicode.

Das einzig Verwirrende ist, dass .NET den Namen eines Zeichensatzes für den Namen einer bestimmten Kodierung dieses Zeichensatzes verwendet. Encoding.Unicode sollte Encoding.UTF16 heißen.

Das ist es für die meisten Verwendungen. Wenn es das ist, was Sie brauchen, hören Sie hier auf zu lesen. Lesen Sie den Spaß Artikel von Joel Spolsky wenn Sie nicht verstehen, was eine Codierung ist.

Spezifischer Bedarf

Nun fragt der Frageautor: "Jeder String wird als Array von Bytes gespeichert, oder? Warum kann ich diese Bytes nicht einfach haben?"

Er will keine Bekehrung.

Aus der C # -Spezifikation :

Die Zeichen- und Zeichenfolgenverarbeitung in C # verwendet Unicode-Codierung. Der Zeichen-Typ repräsentiert eine UTF-16-Code-Einheit und der Zeichen-Typ repräsentiert eine Folge von UTF-16-Code-Einheiten.

Wir wissen also, dass wir das gewünschte Ergebnis erhalten, wenn wir nach der Nullkonvertierung fragen (d. H. Von UTF-16 nach UTF-16):

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

Aber um die Erwähnung von Kodierungen zu vermeiden, müssen wir es anders machen. Wenn ein Zwischendatentyp akzeptabel ist, gibt es hierfür eine konzeptionelle Verknüpfung:

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

Das bringt uns nicht den gewünschten Datentyp, aber Mehrdads Antwort zeigt, wie dieses Char-Array mit BlockCopy in ein Byte-Array konvertiert wird. Dadurch wird die Zeichenfolge jedoch zweimal kopiert! Und es wird auch explizit codierungsspezifischer Code verwendet: der Datentyp System.Char.

Die einzige Möglichkeit, zu den tatsächlichen Bytes zu gelangen, in denen der String gespeichert ist, ist die Verwendung eines Zeigers. Die Anweisung fixed ermöglicht die Adressierung von Werten. Aus der C # -Spezifikation:

[Für] einen Ausdruck vom Typ Zeichenfolge ... berechnet der Initialisierer die Adresse des ersten Zeichens in der Zeichenfolge.

Dazu schreibt der Compiler mit RuntimeHelpers.OffsetToStringData einen Code, der die anderen Teile des String-Objekts überspringt. Um die unformatierten Bytes zu erhalten, erstellen Sie einfach einen Zeiger auf die Zeichenfolge und kopieren Sie die Anzahl der benötigten Bytes.

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

Wie @CodesInChaos hervorhob, hängt das Ergebnis von der Endgültigkeit der Maschine ab. Aber der Frageautor kümmert sich nicht darum.

85
Tom Blodget

Der erste Teil Ihrer Frage (wie Sie die Bytes erhalten) wurde bereits von anderen beantwortet: Schauen Sie im Namensraum System.Text.Encoding nach.

Ich werde Ihre nachfolgende Frage beantworten: Warum müssen Sie eine Codierung auswählen? Warum kann man das nicht von der String-Klasse selbst bekommen?

Die Antwort besteht aus zwei Teilen.

Zuallererst sind die Bytes, die intern von der Zeichenfolgenklasse verwendet werden, egal , und wann immer Sie davon ausgehen, dass sie dies tun, führen Sie wahrscheinlich einen Fehler ein.

Befindet sich Ihr Programm vollständig in der .Net-Welt, müssen Sie sich keine Gedanken darüber machen, ob Sie Byte-Arrays für Zeichenfolgen erhalten, selbst wenn Sie Daten über ein Netzwerk senden. Verwenden Sie stattdessen .Net Serialization, um die Daten zu übertragen. Sie kümmern sich nicht mehr um die tatsächlichen Bytes: Der Serialization-Formatierer erledigt dies für Sie.

Was ist andererseits, wenn Sie diese Bytes an einen Ort senden, für den Sie nicht garantieren können, dass sie Daten aus einem serialisierten .Net-Stream abrufen? In diesem Fall müssen Sie sich definitiv um die Codierung kümmern, da sich dieses externe System offensichtlich darum kümmert. Auch hier spielt es keine Rolle, welche internen Bytes von der Zeichenfolge verwendet werden: Sie müssen eine Codierung auswählen, damit Sie diese Codierung auf der empfangenden Seite explizit angeben können, auch wenn es sich um dieselbe Codierung handelt, die intern von .NET verwendet wird.

Ich verstehe, dass Sie in diesem Fall möglicherweise die tatsächlichen Bytes bevorzugen, die in der Zeichenfolgenvariablen im Speicher gespeichert sind, mit der Idee, dass dadurch möglicherweise Arbeit beim Erstellen Ihres Bytestreams gespart wird. Ich sage es Ihnen jedoch, es ist einfach nicht wichtig, um sicherzustellen, dass Ihre Ausgabe am anderen Ende verstanden wird, und um sicherzustellen, dass Sie explizit mit Ihrer Codierung sein müssen . Wenn Sie wirklich mit Ihren internen Bytes übereinstimmen möchten, können Sie bereits die Codierung Unicode auswählen und diese Leistungsersparnis erzielen.

Das bringt mich zum zweiten Teil ... Auswählen der Unicode-Codierung is, die .Net anweist, die zugrunde liegenden Bytes zu verwenden. Sie müssen diese Codierung auswählen, da bei Erscheinen von neuem Unicode-Plus die .Net-Laufzeit frei sein muss, um dieses neuere, bessere Codierungsmodell zu verwenden, ohne Ihr Programm zu beschädigen. Aber im Moment (und in absehbarer Zukunft) erhalten Sie alles, was Sie wollen, wenn Sie nur die Unicode-Codierung auswählen.

Es ist auch wichtig zu verstehen, dass Ihre Zeichenfolge neu in wire geschrieben werden muss, und dies erfordert zumindest eine Übersetzung des Bitmusters , auch wenn Sie eine passende Codierung verwenden. Der Computer muss Dinge wie Big vs Little Endian, Netzwerk-Bytereihenfolge, Paketierung, Sitzungsinformationen usw. berücksichtigen.

43
Joel Coehoorn

Um zu demonstrieren, dass Mehrdrads Sound Antwort funktioniert, kann sein Ansatz sogar die ngepaarten Ersatzcharaktere (von denen sich viele gegen meine Antwort gestellt hatten, von denen sich aber alle gleichermaßen schuldig fühlen) beibehalten zB System.Text.Encoding.UTF8.GetBytes, System.Text.Encoding.Unicode.GetBytes; diese Codierungsmethoden können beispielsweise die hohen Ersatzzeichen d800 nicht beibehalten, und diese ersetzen nur die hohen Ersatzzeichen durch den Wert fffd):

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

Ausgabe:

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

Versuchen Sie das mit System.Text.Encoding.UTF8.GetBytes oder System.Text.Encoding.Unicode.GetBytes , sie ersetzen nur High-Surrogate-Zeichen durch value fffd

Jedes Mal, wenn es eine Bewegung in dieser Frage gibt, denke ich an einen Serialisierer (sei es von Microsoft oder einer Drittanbieter-Komponente), der Zeichenfolgen beibehalten kann, selbst wenn diese nicht gepaarte Ersatzzeichen enthalten. Ich google dies hin und wieder: Serialisierung ungepaartes Ersatzzeichen .NET . Dadurch verliere ich nicht den Schlaf, aber es ist ärgerlich, wenn hin und wieder jemand meine Antwort als fehlerhaft kommentiert, und ihre Antworten sind gleichermaßen fehlerhaft, wenn es um ungepaarte Ersatzcharaktere geht.

Verdammt, Microsoft hätte gerade System.Buffer.BlockCopy in seinem BinaryFormatter ツ verwenden sollen

谢谢 谢谢

43
Michael Buen

Versuchen Sie dies, viel weniger Code:

System.Text.Encoding.UTF8.GetBytes("TEST String");
39
Nathan

Nun, ich habe alle Antworten gelesen und sie verwendeten Codierung oder eine über Serialisierung, die ungepaarte Ersatzzeichen fallen lässt.

Es ist schlecht, wenn die Zeichenfolge beispielsweise von SQL Server stammt, wo sie aus einem Byte-Array erstellt wurde, in dem beispielsweise ein Kennwort-Hash gespeichert ist. Wenn wir irgendetwas davon löschen, wird ein ungültiger Hash gespeichert, und wenn wir ihn in XML speichern möchten, möchten wir ihn intakt lassen (da der XML-Writer eine Ausnahme für jeden nicht gepaarten Ersatz ablegt, den er findet).

Also verwende ich Base64 Codierung von Byte-Arrays in solchen Fällen, aber hey, im Internet gibt es nur eine Lösung für dieses Problem in C #, und es enthält Fehler und ist nur eine Möglichkeit. Fehler behoben und Prozedur zurückgeschrieben. Hier sind Sie, zukünftige Googler:

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

Erklären Sie auch, warum die Codierung berücksichtigt werden sollte. Kann ich nicht einfach herausfinden, in welchen Bytes die Zeichenfolge gespeichert wurde? Warum diese Abhängigkeit von der Kodierung? !!!

Weil es so etwas wie "die Bytes der Zeichenkette" nicht gibt.

Eine Zeichenfolge (oder allgemeiner ein Text) besteht aus Zeichen: Buchstaben, Ziffern und anderen Symbolen. Das ist alles. Computer wissen jedoch nichts über Charaktere; Sie können nur mit Bytes umgehen. Wenn Sie Text auf einem Computer speichern oder übertragen möchten, müssen Sie die Zeichen daher in Bytes umwandeln. Wie machst du das? Hier kommen Codierungen auf die Bühne.

Eine Kodierung ist nichts anderes als eine Konvention, um logische Zeichen in physikalische Bytes zu übersetzen. Die einfachste und bekannteste Codierung ist ASCII. Sie ist alles, was Sie benötigen, wenn Sie in Englisch schreiben. Für andere Sprachen benötigen Sie umfassendere Codierungen, da derzeit alle Unicode-Varianten die sicherste Wahl sind.

Kurz gesagt, der Versuch, "die Bytes einer Zeichenkette ohne Verwendung von Codierungen zu erhalten", ist so unmöglich wie "einen Text ohne Verwendung einer Sprache zu schreiben".

Übrigens, ich empfehle Ihnen (und allen anderen) nachdrücklich, diese kleine Weisheit zu lesen: Das absolute Minimum, das jeder Softwareentwickler unbedingt, positiv über Unicode und Zeichensätze wissen muss ( Keine Ausreden!)

22
Konamiman

C # zum Konvertieren eines string in ein byte -Array:

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}
21

Sie können den folgenden Code für die Konvertierung zwischen String- und Byte-Array verwenden.

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);
17
Jarvis Stark
byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}
16
gkrogers

Ich bin nicht sicher, aber ich denke, die Zeichenfolge speichert ihre Informationen als ein Array von Zeichen, was mit Bytes ineffizient ist. Insbesondere lautet die Definition eines Zeichens "Repräsentiert ein Unicode-Zeichen".

nimm dieses beispielbeispiel:

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

Beachten Sie, dass die Unicode-Antwort in beiden Fällen 14 Byte beträgt, während die UTF-8-Antwort für die erste nur 9 Byte und für die zweite nur 7 Byte beträgt.

Wenn Sie also nur die von der Zeichenfolge verwendeten Bytes verwenden möchten, verwenden Sie einfach Encoding.Unicode, aber der Speicherplatz wird ineffizient sein.

13
Ed Marty

Mit dem Aufkommen von Span<T> , das mit C # 7.2 veröffentlicht wurde, ist die kanonische Technik zum Erfassen der zugrunde liegenden Speicherdarstellung einer Zeichenfolge in einem verwalteten Byte-Array wie folgt:

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

Das Zurückkonvertieren sollte ein Nichtstarter sein, da dies bedeutet, dass Sie die Daten tatsächlich irgendwie interpretieren, aber der Vollständigkeit halber:

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

Die Namen NonPortableCast und DangerousGetPinnableReference sollten das Argument unterstützen, dass Sie dies wahrscheinlich nicht tun sollten.

Beachten Sie, dass für die Arbeit mit _Span<T>_ das System.Memory NuGet-Paket installiert werden muss.

Unabhängig davon implizieren die tatsächlichen ursprünglichen Fragen- und Folgekommentare, dass der zugrunde liegende Speicher nicht "interpretiert" wird (was meiner Meinung nach bedeutet, dass er nicht geändert oder gelesen wird jenseits der Notwendigkeit, es so zu schreiben, wie es ist), was angibt, dass eine Implementierung der Klasse Stream verwendet werden sollte, anstatt die Daten überhaupt als Zeichenfolgen zu interpretieren.

13
John Rasch

Das Hauptproblem besteht darin, dass eine Glyphe in einer Zeichenfolge 32 Bit (16 Bit für einen Zeichencode) benötigt, ein Byte jedoch nur 8 Bit übrig hat. Eine Eins-zu-Eins-Zuordnung ist nur möglich, wenn Sie sich auf Zeichenfolgen beschränken, die nur ASCII Zeichen enthalten. System.Text.Encoding bietet viele Möglichkeiten, eine Zeichenfolge Byte [] zuzuordnen. Sie müssen eine auswählen, die Informationsverlust vermeidet und von Ihrem Client verwendet werden kann, wenn das Byte [] einer Zeichenfolge zugeordnet werden muss .

Utf8 ist eine beliebte Kodierung, sie ist kompakt und nicht verlustbehaftet.

11
Hans Passant

Verwenden:

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

Das Ergebnis ist:

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103
8
mashet

Wie konvertiere ich eine Zeichenfolge in ein Byte [] in .NET (C #), ohne manuell eine bestimmte Codierung anzugeben?

Ein Zeichenfolge in .NET stellt Text als Folge von UTF-16-Codeeinheiten dar, sodass die Bytes bereits in UTF-16 im Speicher codiert sind.

Mehrdads Antwort

Sie können Mehrdads Antwort verwenden, es wird jedoch tatsächlich eine Codierung verwendet, da die Zeichen UTF-16 sind. Es ruft ToCharArray auf, das beim Betrachten von der Quelle einen char[] erstellt und den Speicher direkt dorthin kopiert. Anschließend werden die Daten in ein Byte-Array kopiert, das ebenfalls zugeordnet ist. Unter der Haube werden also die zugrunde liegenden Bytes zweimal kopiert und ein Zeichen-Array zugewiesen, das nach dem Aufruf nicht verwendet wird.

Tom Blodgets Antwort

Tom Blodgets Antwort ist 20-30% schneller als Mehrdad, da der Zwischenschritt des Zuweisens eines char-Arrays und des Kopierens der Bytes übersprungen wird, Sie jedoch die Option /unsafe verwenden müssen. Wenn Sie absolut keine Codierung verwenden möchten, ist dies der richtige Weg. Wenn Sie Ihr Verschlüsselungs-Login in den Block fixed einfügen, müssen Sie nicht einmal ein separates Byte-Array zuweisen und die Bytes in dieses kopieren.

Warum sollte auch die Codierung berücksichtigt werden? Kann ich nicht einfach herausfinden, in welchen Bytes die Zeichenfolge gespeichert wurde? Warum besteht eine Abhängigkeit von Zeichenkodierungen?

Weil das der richtige Weg ist. string ist eine Abstraktion.

Die Verwendung einer Codierung kann zu Problemen führen, wenn Sie Zeichenfolgen mit ungültigen Zeichen haben. Dies sollte jedoch nicht passieren. Wenn Sie Daten mit ungültigen Zeichen in Ihren String bekommen, machen Sie es falsch. Sie sollten wahrscheinlich zunächst ein Byte-Array oder eine Base64-Codierung verwenden.

Wenn Sie System.Text.Encoding.Unicode verwenden, ist Ihr Code widerstandsfähiger. Sie müssen sich keine Gedanken über die Endianität des Systems machen, auf dem Ihr Code ausgeführt wird. Sie müssen sich keine Sorgen machen, wenn die nächste Version der CLR eine andere interne Zeichencodierung verwendet.

Ich denke, die Frage ist nicht, warum Sie sich um die Kodierung kümmern möchten, sondern warum Sie sie ignorieren und etwas anderes verwenden möchten. Die Codierung soll die Abstraktion einer Zeichenfolge in einer Folge von Bytes darstellen. System.Text.Encoding.Unicode gibt Ihnen eine kleine Codierung in der Endian-Byte-Reihenfolge und führt jetzt und in Zukunft auf jedem System die gleiche Leistung aus.

8
Jason Goemaat

Schnellster Weg

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

EDIT wie Makotosan kommentierte, ist dies nun der beste Weg:

Encoding.UTF8.GetBytes(text)
8
Sunrising

Die Frage von Tom Blodget kommt der Frage von OP am nächsten, die tatsächlich in das Objekt eingeht und die Bytes extrahiert. Ich sage am nächsten, weil es von der Implementierung des String-Objekts abhängt.

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

Klar, aber hier tritt der grundlegende Fehler in der Frage auf. Der String ist ein Objekt, das eine interessante Datenstruktur haben könnte. Wir wissen bereits, dass dies der Fall ist, da ungepaarte Ersatzzeichen gespeichert werden können. Es könnte die Länge speichern. Es könnte einen Zeiger auf jedes der 'gepaarten' Ersatzzeichen behalten, was ein schnelles Zählen ermöglicht. Usw. Alle diese zusätzlichen Bytes sind nicht Teil der Zeichendaten.

Was Sie wollen, sind die Bytes jedes Zeichens in einem Array. Und hier kommt die Codierung ins Spiel. Standardmäßig erhalten Sie UTF-16LE. Wenn Sie sich nicht um die Bytes selbst kümmern, können Sie eine beliebige Codierung auswählen, einschließlich der Standardcodierung, und diese später zurückkonvertieren (unter der Annahme, dass dieselben Parameter wie die Standardcodierung, Codepunkte und Fehlerbehebungen verwendet wurden , erlaubte Dinge wie ungepaarte Leihmütterchen usw.

Aber warum überlässt man die "Kodierung" der Magie? Warum nicht die Codierung angeben, damit Sie wissen, welche Bytes Sie erhalten?

"Why is there a dependency on character encodings?"

Codierung (in diesem Kontext) bedeutet einfach die Bytes, die Ihre Zeichenfolge darstellen. Nicht die Bytes des String-Objekts. Sie wollten die Bytes, in denen die Zeichenfolge gespeichert wurde - hier wurde die Frage naiv gestellt. Sie wollten die Zeichenfolgenbytes in einem zusammenhängenden Array, das die Zeichenfolge darstellt, und nicht alle anderen Binärdaten, die ein Zeichenfolgenobjekt möglicherweise enthält.

Was bedeutet, wie ein String gespeichert wird, ist irrelevant. Sie möchten, dass eine Zeichenfolge in Bytes in einem Byte-Array "codiert" wird.

Ich mag die Antwort von Tom Bloget, weil er Sie in Richtung der Richtung "Bytes of the String Object" geführt hat. Es hängt jedoch von der Implementierung ab, und da er sich die Interna ansieht, ist es möglicherweise schwierig, eine Kopie des Strings wiederherzustellen.

Mehrdads Antwort ist falsch, weil sie auf konzeptioneller Ebene irreführend ist. Sie haben immer noch eine Liste mit codierten Bytes. Seine spezielle Lösung ermöglicht es, ungepaarte Ersatzzeichen beizubehalten - dies ist implementierungsabhängig. Seine spezielle Lösung würde die Bytes der Zeichenkette nicht genau erzeugen, wenn GetBytes die Zeichenkette standardmäßig in UTF-8 zurückliefern würde.


Ich habe es mir anders überlegt (Mehrdads Lösung) - hier werden nicht die Bytes des Strings angezeigt. Vielmehr werden die Bytes des Zeichenarrays abgerufen, das aus der Zeichenfolge erstellt wurde. Unabhängig von der Codierung hat der char-Datentyp in c # eine feste Größe. Dies ermöglicht die Erzeugung eines Byte-Arrays mit konsistenter Länge und die Wiedergabe des Zeichen-Arrays basierend auf der Größe des Byte-Arrays. Wenn die Codierung UTF-8 wäre, aber jedes Zeichen 6 Byte groß wäre, um den größten utf8-Wert aufzunehmen, würde es trotzdem funktionieren. In der Tat spielt die Kodierung des Zeichens keine Rolle.

Es wurde jedoch eine Konvertierung verwendet - jedes Zeichen wurde in ein Feld mit fester Größe (c # - Zeichentyp) eingefügt. Was diese Darstellung ist, spielt jedoch keine Rolle, was technisch die Antwort auf das OP ist. Also - wenn Sie sowieso konvertieren wollen ... Warum nicht "encodieren"?

6
Gerard ONeill

Sie können folgenden Code verwenden, um string in byte array in .NET zu konvertieren

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);
6

Hier ist meine unsichere Implementierung der Konvertierung von String in Byte[]:

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

Es ist viel schneller als das eines akzeptierten Anworters, auch wenn es nicht so elegant ist wie es ist. Hier sind meine Stoppuhr-Benchmarks für über 10000000 Iterationen:

[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

Um es zu verwenden, müssen Sie in den Build-Eigenschaften Ihres Projekts "Unsicheren Code zulassen" ankreuzen. Ab .NET Framework 3.5 kann diese Methode auch als String-Erweiterung verwendet werden:

public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}
4

Wenn Sie wirklich eine Kopie der zugrunde liegenden Bytes einer Zeichenfolge möchten, können Sie eine Funktion wie die folgende verwenden. Das solltest du aber nicht Bitte lies weiter, um herauszufinden warum.

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

Mit dieser Funktion erhalten Sie schnell eine Kopie der Bytes, die Ihrer Zeichenfolge zugrunde liegen. Sie erhalten diese Bytes in der Art und Weise, wie sie auf Ihrem System codiert werden. Diese Codierung ist mit ziemlicher Sicherheit UTF-16LE, aber das ist ein Implementierungsdetail, das Sie nicht interessieren sollten.

Es wäre sicherer, einfacher und zuverlässiger einfach anzurufen,

System.Text.Encoding.Unicode.GetBytes()

Höchstwahrscheinlich führt dies zu demselben Ergebnis, ist einfacher zu tippen und die Bytes werden bei einem Aufruf von immer umgeleitet

System.Text.Encoding.Unicode.GetString()
3
Jodrell

Benutze einfach folgendes:

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
3
alireza amini

Die Zeichenfolge kann aufgrund der folgenden Tatsache auf verschiedene Arten in ein Byte-Array konvertiert werden: .NET unterstützt Unicode, und Unicode standardisiert mehrere unterschiedliche Codierungen, die als UTFs bezeichnet werden. Sie haben unterschiedliche Längen der Bytedarstellung, sind jedoch in dem Sinne äquivalent, dass eine codierte Zeichenfolge in die Zeichenfolge zurückcodiert werden kann. Wenn die Zeichenfolge jedoch mit einer UTF codiert und unter der Annahme einer anderen UTF decodiert wird, kann sie verschraubt werden Nach oben.

.NET unterstützt auch Nicht-Unicode-Codierungen, diese sind jedoch im Allgemeinen nicht gültig (gilt nur, wenn eine begrenzte Untermenge von Unicode-Codepunkten in einer tatsächlichen Zeichenfolge, wie z. B. ASCII, verwendet wird). Intern unterstützt .NET UTF-16, aber für die Darstellung von Streams wird in der Regel UTF-8 verwendet. Es ist auch ein De-facto-Standard für das Internet.

Es überrascht nicht, dass die Serialisierung von Zeichenfolgen in ein Byte-Array und die Deserialisierung von der Klasse System.Text.Encoding unterstützt wird, die eine abstrakte Klasse ist. Die abgeleiteten Klassen unterstützen konkrete Codierungen: ASCIIEncoding und vier UTFs (System.Text.UnicodeEncoding unterstützt UTF-16)

Ref dieser Link.

Zur Serialisierung in ein Array von Bytes mit System.Text.Encoding.GetBytes. Verwenden Sie für die inverse Operation System.Text.Encoding.GetChars. Diese Funktion gibt ein Array von Zeichen zurück. Um eine Zeichenfolge abzurufen, verwenden Sie einen Zeichenfolgenkonstruktor System.String(char[]).
Siehe diese Seite.

Beispiel:

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? :-)
2

Es kommt darauf an, für was Sie die Bytes wollen

Dies liegt daran, dass Tyler so treffend sagte : "Strings sind keine reinen Daten. Sie haben auch Informationen ." In diesem Fall handelt es sich bei den Informationen um eine Codierung, die bei der Erstellung der Zeichenfolge angenommen wurde.

Angenommen, Sie haben Binärdaten (anstelle von Text) in einer Zeichenfolge gespeichert

Dies basiert auf dem Kommentar von OP zu seiner eigenen Frage und ist die richtige Frage, wenn ich die Hinweise von OP auf den Anwendungsfall verstehe.

Das Speichern von Binärdaten in Strings ist aufgrund der oben genannten angenommenen Codierung wahrscheinlich der falsche Ansatz! Welches Programm oder welche Bibliothek auch immer diese Binärdaten in einem string (anstelle eines byte[] - Arrays, das angemessener gewesen wäre) gespeichert hat, hat den Kampf bereits verloren, bevor er begonnen hat. Wenn sie die Bytes in einer REST Anfrage/Antwort an Sie senden oder irgendetwas, das Zeichenfolgen übertragen muss , Base64 wäre der richtige Ansatz.

Wenn Sie eine Textzeichenfolge mit unbekannter Codierung haben

Alle anderen haben diese falsche Frage falsch beantwortet.

Wenn die Zeichenfolge so aussieht, wie sie ist, wählen Sie einfach eine Codierung aus (vorzugsweise eine, die mit UTF beginnt), verwenden Sie die entsprechende Funktion System.Text.Encoding.???.GetBytes() und teilen Sie mit, wem Sie die Bytes geben, für welche Codierung Sie sich entschieden haben.

2
NH.

einfacher Code mit LINQ

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

BEARBEITEN: wie unten kommentiert, ist es kein guter Weg.

sie können es dennoch verwenden, um LINQ mit einer angemesseneren Codierung zu verstehen:

string s = "abc"
byte[] b = s.Cast<byte>().ToArray();
2
Avlin

Zwei Wege:

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

Und,

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

Ich neige dazu, die untere öfter zu verwenden als die obere, habe sie nicht auf Geschwindigkeit überprüft.

2
harmonik
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
user1120193

Ein Zeichen ist sowohl ein Suchschlüssel für eine Schriftartentabelle als auch eine lexikalische Tradition, wie z. B. Reihenfolge, Groß- und Kleinschreibung usw.

Folglich ist ein Zeichen kein Byte (8 Bits) und ein Byte ist kein Zeichen. Insbesondere können die 256 Permutationen eines Bytes nicht die Tausenden von Symbolen in einigen geschriebenen Sprachen aufnehmen, geschweige denn in allen Sprachen. Daher wurden verschiedene Verfahren zum Codieren von Zeichen entwickelt. Einige codieren für eine bestimmte Sprachklasse (ASCII-Codierung). mehrere Sprachen unter Verwendung von Codepages (Extended ASCII); oder ehrgeizig alle Sprachen, indem Sie nach Bedarf zusätzliche Bytes (Unicode) hinzufügen.

In einem System wie .NET Framework impliziert ein String eine bestimmte Zeichenkodierung. In .NET ist diese Codierung Unicode. Da das Framework standardmäßig Unicode liest und schreibt, ist die Zeichencodierung in .NET normalerweise nicht erforderlich.

Um jedoch eine Zeichenfolge aus einem Bytestrom in das System zu laden, müssen Sie die Quellcodierung kennen, um sie zu interpretieren und anschließend korrekt zu übersetzen Kauderwelsch). Wenn eine Zeichenfolge in eine externe Quelle geschrieben wird, wird sie in einer bestimmten Codierung geschrieben.

0
George

Von byte[] bis string:

        return BitConverter.ToString(bytes);
0
Piero Alberto

Verwenden Sie die folgende Lösung, um eine Zeichenfolge in ein Byte [] zu konvertieren:

string s = "abcdefghijklmnopqrstuvwxyz";
byte[] b = System.Text.UTF32Encoding.GetBytes(s);

Ich hoffe, es hilft.

0

Ich habe eine Visual Basic-Erweiterung geschrieben, die der akzeptierten Antwort ähnelt, aber .NET-Speicher und Marshalling direkt für die Konvertierung verwendet, und sie unterstützt Zeichenbereiche, die in anderen Methoden nicht unterstützt werden, z. B. UnicodeEncoding.UTF8.GetString oder UnicodeEncoding.UTF32.GetString oder sogar MemoryStream and BinaryFormatter (ungültige Zeichen wie: ???? & ChrW(55906) & ChrW(55655)):

<Extension> _
Public Function ToBytesMarshal(ByRef str As String) As Byte()
    Dim gch As GCHandle = GCHandle.Alloc(str, GCHandleType.Pinned)
    Dim handle As IntPtr = gch.AddrOfPinnedObject
    ToBytesMarshal = New Byte(str.Length * 2 - 1) {}
    Try
        For i As Integer = 0 To ToBytesMarshal.Length - 1
            ToBytesMarshal.SetValue(Marshal.ReadByte(IntPtr.Add(handle, i)), i)
        Next
    Finally
        gch.Free()
    End Try
End Function

<Extension> _
Public Function ToStringMarshal(ByRef arr As Byte()) As String
    Dim gch As GCHandle = GCHandle.Alloc(arr, GCHandleType.Pinned)
    Try
        ToStringMarshal = Marshal.PtrToStringAuto(gch.AddrOfPinnedObject)
    Finally
        gch.Free()
    End Try
End Function
0