Welche Art von Codierung kann ich verwenden, um eine Zeichenfolge kürzer zu machen?


13

Ich bin an der Codierung einer Zeichenfolge interessiert und bin gespannt, ob es eine Codierungsart gibt, die nur alphanumerische und numerische Zeichen enthält und vorzugsweise die Anzahl der zur Darstellung der Zeichenfolge erforderlichen Zeichen verkürzt.

Bisher habe ich mir überlegt, ob ich dazu Base64-Codierung verwenden soll, aber es scheint, dass meine Zeichenfolge länger wird und manchmal enthält, ==was ich vermeiden möchte. Beispiel:

Testname | 120101

wird

dGVzdCBuYW1lfDEyMDEwMQ ==

Das geht von 16 bis 24 Zeichen und enthält nicht alphanumerische Zeichen.

Kennt jemand eine andere Art der Codierung, die ich verwenden könnte, um meine Anforderungen zu erfüllen? Bonuspunkte, wenn es entweder in das .NET Framework integriert ist oder eine Bibliothek eines Drittanbieters vorhanden ist, die die Codierung übernimmt.


1
kann keinen Verlust weniger Komprimierung wie Huffman-Codierung verwenden !! Sie sind ideal für Texte geeignet ... aber am Ende sollten Sie wirklich über diese Mutation Bescheid wissen, die Sie vorgenommen haben, um den Text zurückzubekommen.

6
Sie beschreiben Komprimierung, nicht Codierung
Andy Smith

@ Andrew - Ok, irgendwelche Vorschläge?
Abe Miessler

Antworten:


30

Das letzte '=' oder '==' in Base64 dient nur dazu, die Anzahl der Zeichen auf ein Vielfaches von 4 zu setzen. Sie können es entfernen, da Sie es später jederzeit wieder zurücksetzen können. Beachten Sie, dass Base64 so genannt wird, weil es 64 verschiedene Zeichen verwendet. Großbuchstaben, Kleinbuchstaben und Ziffern, das sind 62. Base64 verwendet also auch '/' und '+', die möglicherweise zu Ihrer Rechnung passen oder nicht.

Wenn Sie beliebige Folgen von Bytes in alphanumerische Zeichen codieren möchten, gibt es im Allgemeinen irgendwo eine Längenerweiterung, da 256 mögliche Werte für ein Byte und nur 62 alphanumerische Zeichen vorhanden sind. Es wird manchmal das Pigeonhole-Prinzip genannt . Ein Codierungsschema muss eine durchschnittliche Längenerweiterung eines Faktors log 256 / log 62 = 1,344 aufweisen (Durchschnitt über alle Folgen von Bytes); Andernfalls bedeutet dies, dass einige Tauben irgendwo zu Tode zerquetscht werden und Sie sie nicht ohne Schaden zurückbekommen (was bedeutet: zwei unterschiedliche Zeichenfolgen, die für dieselbe codiert sind, sodass die Dekodierung nicht zuverlässig funktioniert).

Nun ist es durchaus möglich, dass Ihre Zeichenfolgen nicht genau "Sequenzen von gleichmäßig zufälligen Bytes" sind. Ihre Zeichenfolgen haben eine Bedeutung, was bedeutet, dass die größtmögliche Folge von Bytes nicht auftritt, da sie bedeutungslos sind. Auf dieser Basis können Sie wahrscheinlich ein Codierungsschema entwickeln, das eine geringere Längenerweiterung aufweist als generisches Base64 (oder Base62, wenn Sie sich an strenge alphanumerische Zeichen halten müssen). Dies ist eine verlustfreie Datenkomprimierung . Es arbeitet über ein klar definiertes Wahrscheinlichkeitsmodell dessen, was als Eingabe erscheinen kann.

Zusammenfassung: Ein generisches Schema zum Codieren von Zeichenfolgen in alphanumerische Sequenzen, sodass keine oder nur eine geringe Längenerweiterung auftritt, kann nicht existieren. es ist eine mathematische Unmöglichkeit. Möglicherweise gibt es ein spezielles Schema, das auf die Art der erwarteten Eingabezeichenfolge zugeschnitten ist (da Sie jedoch nicht angeben, auf welche Art von Zeichenfolge Sie möglicherweise stoßen, kann Ihnen niemand dabei helfen).


1
+1, ausgezeichnete Erklärung. Ich wusste nicht , über die =/ ==der Länge bezogen ist, die ein Vielfaches von 4 zu sein , die ich in der Lage sein , dies zu umgehen , für meine Bedürfnisse
Abe Miessler

Wohlgemerkt, dies setzt einen Mangel an Schubladen voraus. Unicode hat viele Buchstaben. Wir brauchen wirklich ein besseres Verständnis für das eigentliche Problem.
MSalters

@ Tom Wie haben Sie den durchschnittlichen Längenerweiterungsfaktor mithilfe der Protokollteilung berechnet? Basierend auf dem Diagramm in en.wikipedia.org/wiki/Base64 ist es völlig intuitiv sinnvoll, dass für jedes nicht codierte Zeichen 4/3 Zeichen in Base64 benötigt werden, um es darzustellen. Ich frage mich nur, wie Sie mit der Mathematik zu demselben Ergebnis gekommen sind ... danke :)
Jonathan Lin

Meine schlechte, dumme Frage. log (256) = 8 Bit, log (64) = 6 Bit, daher beträgt das Verhältnis 8/6 = 4/3 = 1,333 für Base64. Prost.
Jonathan Lin

4

Das Neucodieren von Zeichen erfolgt im Allgemeinen, wenn das empfangende System sie nicht verarbeiten kann. Zum Beispiel repräsentiert BASE64 Daten unter Verwendung von 6 Bits (2 6 , also 64) Zeichen, um längere Datensequenzen darzustellen (das manchmal erscheinende "==" am Ende füllt die Ausrichtung auf). Dies liegt daran, dass Ihre Bilddatei in E-Mails möglicherweise 0xFE enthält und Ihr Mailserver diese (oder ein anderes traditionell nicht druckbares Zeichen) nicht zufrieden überträgt.

Es gibt keine Codierung, die "die Größe reduziert". Codierungen sind nur Zuordnungen von Bits zu dem Zeichen, das sie darstellen. Das heißt, ASCII ist ein 7-Bit-Zeichensatz (Codierung), der häufig in 8 Bit Speicherplatz gespeichert wird. Wenn Sie die von Ihnen akzeptierten Bereiche einschränken, können Sie auch die Steuerzeichen aussortieren.

Wenn Sie diese Methode verwenden, müssen Sie die Dinge auf Bitebene ausschreiben, und sie spielt auch ein bisschen mit der Maschinengeschwindigkeit und den Anweisungen, da alle modernen Maschinen Ausrichtungen haben, die ein Vielfaches von 8 Bits sind. Aus diesem Grund ist Unicode beispielsweise UTF-8, UTF-16 und UTF-32.

Wenn Sie dies aus Sicherheitsgründen tun (deshalb haben Sie es auf Security.SE veröffentlicht, oder?), Filtern Sie die Dinge einfach heraus und speichern Sie sie normal. Wenn Sie dies tun, um Platz zu sparen, prüfen Sie, ob der gesamte zusätzliche Code und die langsamere Zugriffszeit (da die meisten Einträge Adressgrenzen überschreiten) die Platzersparnis wert sind.

Im Übrigen ist das Folgende ein Ausschnitt aus einem CS-Kurs, in dem wir ASCII von 8-Bit-Speicher in 7-Bit konvertieren mussten:

    memset(dest,0x00,8);
    memcpy(dest, source, length);

    for (int i = 0; i < 8; i++) {
            if (dest[i] & 0x80) {
                    fprintf(stderr, "%s: %s\n", dest, "Illegal byte sequence");
                    exit(EILSEQ);
            }
    }

    dest[0] = 0x7F & dest[0] | 0x80 & dest[1] << 7;
    dest[1] = 0x3F & dest[1] >> 1 | 0xC0 & dest[2] << 6;
    dest[2] = 0x1F & dest[2] >> 2 | 0xE0 & dest[3] << 5;
    dest[3] = 0x0F & dest[3] >> 3 | 0xF0 & dest[4] << 4;
    dest[4] = 0x07 & dest[4] >> 4 | 0xF8 & dest[5] << 3;
    dest[5] = 0x03 & dest[5] >> 5 | 0xFC & dest[6] << 2;
    dest[6] = 0x01 & dest[6] >> 6 | 0xFE & dest[7] << 1;
    dest[7] = 0x00; //Clearing out

2

Sie können die Daten mit z. B. gzip, bzip2 oder lzma komprimieren und dann base64 durchlaufen, um den verwendeten Zeichensatz einzuschränken. Dies ist nur bei größeren Zeichenfolgen mit Hunderten von Bytes oder mehr von Vorteil.


1

Warum nicht die LZ-Komprimierung verwenden? Dies kann eine anständige Methode zum Komprimieren einer Zeichenfolge sein, wäre jedoch bei langen Zeichenfolgen effizienter. Wie lang ist die Zielzeichenfolge, die Sie codieren möchten?


Wie ist die LZ-Komprimierung im Vergleich zu gzip oder bzip2, die im Attir-Vorschlag erwähnt werden?
NoChance

gzip basiert auf LZ und Huffman Coding. mehr auf LZ en.wikipedia.org/wiki/LZ77
A.Rashad
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.