c# string - Wie bekomme ich eine konsistente Byte-Darstellung von Zeichenfolgen in C #, ohne manuell eine Codierung festzulegen?




15 Answers

Im Gegensatz zu den Antworten hier müssen Sie sich nicht um die Kodierung kümmern, wenn die Bytes nicht interpretiert werden müssen!

Wie Sie bereits erwähnt haben, ist Ihr Ziel, einfach "zu bekommen, in welche Bytes die Zeichenfolge gespeichert wurde" .
(Und natürlich, um die Zeichenfolge aus den Bytes neu zu konstruieren.)

Für diese Ziele verstehe ich ehrlich gesagt nicht , warum Leute dir immer wieder sagen, dass du die Kodierungen benötigst. Sie müssen sich sicherlich nicht um Kodierungen kümmern.

Tun Sie das 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;
}

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 versuchen, die Bytes irgendwie zu interpretieren , was Sie offensichtlich nicht erwähnt haben, beabsichtigen Sie zu tun, dann ist an dieser Vorgehensweise nichts falsch! Sich über Codierungen Sorgen zu machen, macht dein Leben ohne wirklichen Grund komplizierter.

Zusätzlicher Vorteil für diesen Ansatz:

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

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

Wenn Sie jedoch eine bestimmte Kodierung verwendet hätten, hätten Sie Probleme mit der Kodierung / Dekodierung ungültiger Zeichen gehabt.

symbol prefix

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

Ich werde die Zeichenfolge verschlüsseln. Ich kann es ohne Konvertierung verschlüsseln, aber ich würde immer noch gerne wissen, warum die Codierung hier zum Einsatz kommt.

Auch warum sollte Codierung in Betracht gezogen werden? Kann ich nicht einfach herausfinden, in welchen Bytes die Zeichenfolge gespeichert wurde? Warum besteht eine Abhängigkeit von Zeichenkodierungen?




Die angenommene Antwort ist sehr, sehr kompliziert. Verwenden Sie dazu die enthaltenen .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);

Erfinde das Rad nicht neu, wenn du nicht musst ...




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

Joel hat einen Beitrag dazu:

joelonsoftware.com/articles/Unicode.html




Nur um zu demonstrieren, dass Mehrdrads Klangantwort funktioniert, kann seine Herangehensweise sogar die [BinaryFormatter beibehalten (von denen viele gegen meine Antwort System.Text.Encoding.UTF8.GetBytes , von denen aber alle gleichermaßen schuldig sind, zB System.Text.Encoding.UTF8.GetBytes , System.Text.Encoding.Unicode.GetBytes ; diese Codierungsmethoden können die hohen d800 nicht d800 und ersetzen nur hohe fffd 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 Ersatzzeichen mit Wert fffd

Jedes Mal, wenn eine Bewegung in dieser Frage auftritt, denke ich immer noch an einen Serialisierer (sei es von Microsoft oder von einer Drittanbieterkomponente), der Zeichenfolgen beibehalten kann, selbst wenn er nicht ersetzte Ersatzzeichen enthält. Ich google dies hin und wieder: Serialisierung ungepaartes Ersatzzeichen .NET . Das lässt mich nicht schlafen, aber es ist irgendwie nervig, wenn ab und zu jemand meine Antwort kommentiert, dass sie fehlerhaft ist, aber ihre Antworten sind ebenso fehlerhaft, wenn es um ungepackte Ersatzcharaktere geht.

Darn, Microsoft hätte einfach System.Buffer.BlockCopy in seinem BinaryFormatterツ verwenden sollen

谢谢!




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

Ich werde auf Ihre Follow-up-Frage eingehen: Warum müssen Sie eine Codierung auswählen? Warum kannst du das nicht von der String-Klasse selbst bekommen?

Die Antwort besteht aus zwei Teilen.

Zuallererst sind die Bytes, die intern von der String-Klasse verwendet werden, nicht wichtig , und wann immer Sie davon ausgehen, dass Sie dies tun, führen Sie wahrscheinlich einen Bug ein.

Wenn sich Ihr Programm vollständig innerhalb der .Net-Welt befindet, müssen Sie sich keine Gedanken darüber machen, Byte-Arrays für Strings überhaupt zu erhalten, selbst wenn Sie Daten über ein Netzwerk senden. Verwenden Sie stattdessen die .Net-Serialisierung, um sich um die Übertragung der Daten zu kümmern. Sie müssen sich nicht mehr um die tatsächlichen Bytes kümmern: Der Serialisierungsformatierer erledigt das für Sie.

Auf der anderen Seite, was passiert, wenn Sie diese Bytes irgendwo senden, die Sie nicht garantieren können, Daten aus einem serialisierten .Net-Stream einzuziehen? In diesem Fall müssen Sie sich auf jeden Fall um die Kodierung kümmern, denn offensichtlich kümmert sich dieses externe System darum. Auch hier sind die internen Bytes, die von der Zeichenfolge verwendet werden, egal: Sie müssen eine Codierung auswählen, damit Sie diese Codierung auf der Empfängerseite 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 lieber die tatsächlichen Bytes verwenden möchten, die von der String-Variablen im Speicher gespeichert werden, wo dies möglich ist, mit der Idee, dass es beim Erstellen Ihres Byte-Streams etwas Arbeit sparen könnte. Wie auch immer, ich sage es Ihnen, es ist einfach nicht wichtig im Vergleich zu sicherzustellen, dass Ihre Ausgabe am anderen Ende verstanden wird, und um sicherzustellen, dass Sie explizit mit Ihrer Kodierung kommunizieren müssen. Wenn Sie Ihre internen Bytes wirklich abgleichen möchten, können Sie außerdem einfach die Unicode Codierung auswählen und diese Leistungseinsparungen erzielen.

Das bringt mich zum zweiten Teil ... die Unicode Codierung auszuwählen, sagt .Net, die zugrunde liegenden Bytes zu verwenden. Sie müssen diese Kodierung wählen, denn wenn ein neugefädeltes Unicode-Plus herauskommt, muss die .Net-Laufzeit frei sein, um dieses neuere, bessere Kodierungsmodell zu verwenden, ohne Ihr Programm zu unterbrechen. Aber für den Moment (und die absehbare Zukunft), nur die Wahl der Unicode-Codierung gibt Ihnen, was Sie wollen.

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




Bitte erläutern 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 Zeichenfolge" 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 also Text mithilfe eines Computers speichern oder übertragen möchten, müssen Sie die Zeichen in Bytes umwandeln. Wie machst du das? Hier kommen Codierungen zum Einsatz.

Eine Codierung ist nichts anderes als eine Konvention, um logische Zeichen in physikalische Bytes zu übersetzen. Die einfachste und am besten bekannte Kodierung ist ASCII, und es ist alles, was Sie brauchen, wenn Sie in Englisch schreiben. Für andere Sprachen benötigen Sie umfangreichere Kodierungen, wobei Unicode-Varianten heutzutage die sicherste Wahl sind.

Kurz gesagt, der Versuch, "die Bytes eines Strings ohne Verwendung von Codierungen zu erhalten", ist genauso unmöglich wie "einen Text schreiben, ohne irgendeine Sprache zu verwenden".

Übrigens empfehle ich Ihnen (und allen anderen) sehr, dieses kleine Stück Weisheit zu lesen: joelonsoftware.com/articles/Unicode.html




byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}



I'm not sure, but I think the string stores its info as an array of Chars, which is inefficient with bytes. Specifically, the definition of a Char is "Represents a Unicode character".

take this example sample:

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

Take note that the Unicode answer is 14 bytes in both instances, whereas the UTF-8 answer is only 9 bytes for the first, and only 7 for the second.

So if you just want the bytes used by the string, simply use Encoding.Unicode , but it will be inefficient with storage space.




Fastest way

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

EDIT as Makotosan commented this is now the best way:

Encoding.UTF8.GetBytes(text)



You can use following code to convert a string to a byte array in .NET

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



Here is my unsafe implementation of String to 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;
}

It's way faster than the accepted anwser's one, even if not as elegant as it is. Here are my Stopwatch benchmarks over 10000000 iterations:

[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

In order to use it, you have to tick "Allow Unsafe Code" in your project build properties. As per .NET Framework 3.5, this method can also be used as String extension:

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



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



Simply use this:

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



The string can be converted to byte array in few different ways, due to the following fact: .NET supports Unicode, and Unicode standardizes several difference encodings called UTFs. They have different lengths of byte representation but are equivalent in that sense that when a string is encoded, it can be coded back to the string, but if the string is encoded with one UTF and decoded in the assumption of different UTF if can be screwed up.

Also, .NET supports non-Unicode encodings, but they are not valid in general case (will be valid only if a limited sub-set of Unicode code point is used in an actual string, such as ASCII). Internally, .NET supports UTF-16, but for stream representation, UTF-8 is usually used. It is also a standard-de-facto for Internet.

Not surprisingly, serialization of string into an array of byte and deserialization is supported by the class System.Text.Encoding , which is an abstract class; its derived classes support concrete encodings: ASCIIEncoding and four UTFs ( System.Text.UnicodeEncoding supports UTF-16)

Ref this link.

For serialization to an array of bytes using System.Text.Encoding.GetBytes . For the inverse operation use System.Text.Encoding.GetChars . This function returns an array of characters, so to get a string, use a string constructor System.String(char[]) .
Ref this page.

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



From byte[] to string :

        return BitConverter.ToString(bytes);



Related

c# .net string

Tags

c#   .net   string