Laden...

Hex in lesbare Zeichen umwandeln (möglichst kompakt)

Erstellt von baer999 vor 9 Jahren Letzter Beitrag vor 9 Jahren 2.296 Views
B
baer999 Themenstarter:in
375 Beiträge seit 2007
vor 9 Jahren
Hex in lesbare Zeichen umwandeln (möglichst kompakt)

Hallo,

ich möchte gern einen Hex Wert, wie bspw.:

BFEBFBFF000206A7

umwandeln (zwecks Komprimierung), dabei muss aber die Lesbarkeit gewährleistet sein (also keine ASCII Konvertierung, da hier Zeichen enthalten sind, die "nicht lesbar" sind).

Mir würde es reichen, wenn aus dem obigen 16-stelligen Bsp. nach der Umwandlung 10-12 Zeichen übrig bleiben würden.

Hat da jemand eine Idee?

Der Pool für die Zeichen soll alle Buchstaben und alle Zahlen beinhalten.

D
216 Beiträge seit 2009
vor 9 Jahren

Hex String -> Byte[] -> Base64 String

Das würde für dein Beispiel v+v7/wACBqc= (12 Zeichen) ergeben.

Wenn dir das zu unleserlich ist, kannst du auch base32 nehmen (BVQVRVS0041L7, 13 Zeichen).

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo baer999,

es gibt 128-33 = 95 druckbare (7-Bit)ASCII-Zeichen. Also mehr als bei base64 und erst recht base32 verwendet werden. Wenn man einen noch größeren Zeichensatz als 7-bit-ASCII verwenden kann, um so besser. Anderseits sollte man optisch ähnliche Zeichen, z.B. 1 und I oder 0 und O aus dem Zeichenvorrat entfernen. Im Beispiel bezeichne ich die Anzahl der gewählten Zeichen mit N, denn das Verfahren geht mit jeder beliebigen Zahl an Zeichen. Je mehr Zeichen, desto kompakter das Ergebnis.

Du packst alle gewünschten Zeichen in ein Array (die Reihenfolge ist im Prinzip egal). Dann betrachtest du den Hex-String als eine große Hexzahl. Du könntest den Hex-String z.B. in einen BigInteger konvertieren. Dann rechnest du die Zahl modulo N und verwendest das Ergebnis als Index in das Array, um das erste Zeichen zu ermitteln. Dann teilst du die Zahl durch N und rechnest vom Ergebnis wieder Modulo N für das zweite Zeichen und das immer so weiter, bis das Ergebnis des wiederholten Teilens 0 ist. Das ist aus meiner Sicht die kompaktestmögliche Darstellung.

Kompakter kann man m.E. nur werden, wenn man die Eingabe für sich genommen komprimiert, z.B. per ZipStream. Aber die Frage ist, ob der dabei nötige Verwaltungs-Overhead die Ersparnis nicht wieder (mehr als) auffrisst. Die mögliche Ersparnis hängt von der enthaltenen Redundanz ab. Wenig redundante Eingabestrings/-zahlen werden durch die Kompression sogar (etwas) länger.

herbivore

B
baer999 Themenstarter:in
375 Beiträge seit 2007
vor 9 Jahren

Super Tipps, vielen dank!

Ich habe nun eine Base62 implementiert, habe jedoch noch Probleme bei der Rückrechnung, sieht da jemand, wo ich den logischen Fehler drin habe?

Bsp. war:

ToBase62(311299) => XYi

ABER

FromBase62(XYi) => 230534

Quellcode:

        private string Base62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

        public string ToBase62(Int64 i)
        {
            StringBuilder sb = new StringBuilder();  
            Int64 rest = i;

            while (rest / 62 != 0)
            {
                long index = rest % 62;
                sb.Append(Base62[(int)index]);

                rest = rest / 62;
            }

            return sb.ToString();
        }

        public Int64 FromBase62(String s)
        {
            char[] chrs = s.ToCharArray();
            int m = chrs.Length - 1;
            int n = 62;
            int x;
            int rtn = 0;

            foreach (char c in chrs)
            {
                x = Base62.IndexOf(c);

                rtn += x * (Convert.ToInt32(Math.Pow(n, m)));

                m--;
            }

            return rtn; 
        }

Danke !!!

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo baer999,

du musst die Schleife durchlaufen, solange rest noch nicht Null ist, sonst schluckst du das letzte Zeichen. Ob das der einzige Fehler ist, weiß ich nicht, aber das lässt sich ja leicht im Debugger herausbekommen, siehe [Artikel] Debugger: Wie verwende ich den von Visual Studio?.

Davon abgesehen birgt die Verwendung von Math.Pow das unnötige Risiko von Rundungsfehlern. So wie du in der einen Richtung den Rest sukzessive durch 62 teilst, solltest du in der anderen Richtung das Zwischenergebnis sukzessive mit 62 multiplizieren.

Apropos 62: Das ist nicht gerade DRY. Ich würde eine Konstante verwenden. Oder noch besser Array.Length verwenden. Dann passt die Berechnung immer zu der tatsächlich im Array enthaltenen Anzahl von Zeichen.

herbivore