Gibt es eine Standardtechnik zum Packen von Binärdaten in eine UTF-16-Zeichenfolge?

8

(In .NET) Ich habe willkürliche Binärdaten in einem Byte [] (ein Bild zum Beispiel) gespeichert. Jetzt muss ich diese Daten in einer Zeichenfolge speichern (ein "Kommentar" -Feld einer alten API). Gibt es eine Standardtechnik für packen diese Binärdaten in eine Zeichenkette ? Mit "packen" meine ich, dass bytes.Length / 2 etwa gleich groß ist wie packed.Length ; weil zwei Bytes mehr oder weniger ein einzelnes Zeichen sind.

Die zwei "offensichtlichen" Antworten erfüllen nicht alle Kriterien:

%Vor%

verwendet die Zeichenkette nicht sehr effizient, da nur 64 Zeichen von ungefähr 60.000 Zeichen verwendet werden (mein Speicher ist ein System.String ). Geht mit

%Vor%

verwendet die Zeichenfolge besser, funktioniert jedoch nicht für Daten, die ungültige Unicode-Zeichen enthalten (z. B. nicht übereinstimmende Ersatzpaare). Dieser MSDN-Artikel zeigt diese genaue (schlechte) Technik.

Schauen wir uns ein einfaches Beispiel an:

%Vor%

In diesem Fall sind Bytes und utf16_bytes identisch, weil die ursprünglichen Bytes eine UTF-16-Zeichenfolge waren. Wenn Sie die gleiche Prozedur mit der base64-Codierung ausführen, erhalten Sie ein Array mit 16 Elementen base64_bytes .

Wiederholen Sie den Vorgang mit ungültigen UTF-16-Daten:

%Vor%

Sie werden feststellen, dass utf16_bytes nicht mit den ursprünglichen Daten übereinstimmt.

Ich habe Code geschrieben, der U + FFFD als Escape vor ungültigen Unicode-Zeichen verwendet. es funktioniert, aber ich würde gerne wissen, ob es eine Standard-Technik gibt, als etwas, das ich mir alleine ausgedacht habe. Ganz zu schweigen von der Tatsache, dass ich catch in DecoderFallbackException nicht als Möglichkeit zur Erkennung ungültiger Zeichen empfinde.

Ich denke, Sie könnten dies als "Basis-BMP" oder "Basis-UTF-16" -Kodierung bezeichnen (unter Verwendung aller Zeichen in der Unicode Basic Multilingual Plane). Ja, im Idealfall würde ich Shawn Steeles Rat befolgen und weitergeben byte [] .

Ich werde den Vorschlag von Peter Housel als die "richtige" Antwort nehmen, weil er der einzige ist, der einer "Standardtechnik" nahekommt.

Bearbeiten base16k looks noch besser. Jim Beveridge hat eine Implementierung .

    
Dan 24.02.2015, 02:14
quelle

7 Antworten

4

Ich bin nach dem Lesen Ihrer Frage auf Base16k gestoßen. Nicht streng ein Standard, aber es scheint gut zu funktionieren und war einfach genug, um in C # zu implementieren.

    
3 revs, 3 users 80%Neil 22.10.2016, 02:13
quelle
10

Darf ich vorschlagen, dass Sie base64 verwenden? Es ist möglicherweise nicht der effizienteste Weg, dies zu tun, aber es hat seine Vorteile:

  1. Ihre Sorgen über den Code sind vorbei.
  2. Sie haben die wenigsten Kompatibilitätsprobleme mit anderen Spielern, falls es welche gibt.
  3. Sollte die codierte Zeichenkette während der Konvertierung, des Exports, des Imports, der Sicherung, der Wiederherstellung oder was auch immer als ASCII betrachtet werden, haben Sie auch keine Probleme.
  4. Sollten Sie jemals tot umgefallen sein oder unter einem Bus gelandet sein, wird jeder Programmierer, der jemals das Kommentarfeld in die Finger bekommt, sofort wissen, dass es base64 ist und nicht davon ausgehen, dass alles verschlüsselt ist oder etwas.
Dave Van den Eynde 03.03.2016 07:46
quelle
3

Denken Sie zunächst daran, dass Unicode nicht 16 Bits bedeutet. Die Tatsache, dass System.String intern UTF-16 verwendet, ist weder hier noch dort. Unicode-Zeichen sind abstrakt - sie erhalten nur Bit-Darstellungen durch Kodierungen.

Sie sagen "mein Speicher ist ein System.String" - wenn das der Fall ist, können Sie nicht über Bits und Bytes sprechen, nur Unicode-Zeichen. System.String hat sicherlich seine eigene interne Kodierung, aber (theoretisch) könnte das anders sein.

Wenn Sie außerdem glauben, dass die interne Darstellung von System.String für Base64-codierte Daten zu speicherineffizient ist, warum machen Sie sich dann auch keine Gedanken über lateinische / westliche Zeichenfolgen?

Wenn Sie binäre Daten in einem System.String speichern möchten, benötigen Sie eine Zuordnung zwischen Sammlungen von Bits und Zeichen.

Option A: Es gibt eine vorgefertigte Version in Form der Base64-Kodierung. Wie Sie bereits erwähnt haben, codiert dies sechs Datenbits pro Zeichen.

Option B: Wenn Sie mehr Bits pro Zeichen packen möchten, müssen Sie ein Array (oder eine Codierung) von 128, 256, 512 usw. Unicode-Zeichen erstellen und 7, 8, 9 usw. Bits packen von Daten pro Zeichen. Diese Zeichen müssen echte Unicode-Zeichen sein.

Um Ihre Frage einfach zu beantworten, ja es gibt einen Standard, es ist Base64-Codierung.

Ist das ein echtes Problem? Haben Sie Perf-Daten, um Ihre Idee zu unterstützen, Base64 nicht zu verwenden?

    
stusmith 21.03.2009 13:16
quelle
1

Hier ist eine C # -Version von Jim Beveridges C ++ Implementierung :

%Vor%     
Ðаn 24.02.2015 16:03
quelle
1

Sie könnten die Binärdaten als UTF-8b . Die UTF-8b-Kodierung geht davon aus, dass es sich bei den Bytes um UTF-8-Multibyte-Sequenzen handelt, hat aber eine Fallback-Kodierung für Dinge, die es nicht gibt.

    
Peter S. Housel 15.03.2009 03:30
quelle
0

Ich habe mich mit direkten Char-Arrays herumalbern lassen, und Ihr einziger fehlgeschlagener Fall funktioniert mit meiner Implementierung. Der Code wurde gut getestet: also machen Sie zuerst Ihre Tests.

Sie könnten dies beschleunigen, indem Sie unsicheren Code verwenden. Aber ich bin sicher, UnicodeEncoding ist genauso langsam (wenn nicht langsamer).

%Vor%

Hier ist ein Testcode:

%Vor%

Der Test funktioniert, aber Sie müssen ihn mit Ihrer API-Funktion testen.

    
Jonathan C Dickinson 19.03.2009 10:15
quelle
0

Es gibt eine andere Möglichkeit, diese Einschränkung zu umgehen: obwohl ich nicht sicher bin, wie gut es funktionieren würde.

Zuerst müssen Sie herausfinden, welche Art von String der API-Aufruf erwartet - und wie die Struktur dieser Zeichenfolge ist. Wenn ich ein einfaches Beispiel nehme, betrachten wir die .Net-Zeichenkette:

  • Int32 _length;
  • byte [] _data;
  • byte_terminator = 0;

Fügen Sie Ihrem API-Aufruf eine Überladung hinzu:

%Vor%

Wenn Sie die Byte-Version aufrufen müssen, können Sie Folgendes tun:

%Vor%     
Jonathan C Dickinson 19.03.2009 10:26
quelle

Tags und Links