Jakiego rodzaju kodowania mogę użyć, aby skrócić łańcuch?

13

Interesuje mnie kodowanie łańcucha, który mam i jestem ciekawy, czy istnieje rodzaj kodowania, który może być użyty, który będzie zawierał tylko znaki alfanumeryczne i najlepiej skróciłby liczbę znaków potrzebnych do przedstawienia łańcucha.

Do tej pory zastanawiałem się nad użyciem do tego kodowania Base64, ale wydaje się, że mój łańcuch jest dłuższy i czasami zawiera to, ==czego chciałbym uniknąć. Przykład:

nazwa testu | 120101

staje się

dGVzdCBuYW1lfDEyMDEwMQ ==

który ma od 16 do 24 znaków i zawiera znaki niealfanumeryczne.

Czy ktoś wie o innym rodzaju kodowania, którego mógłbym użyć, który spełni moje wymagania? Punkty bonusowe, jeśli są wbudowane w platformę .NET lub istnieje biblioteka innej firmy, która wykona kodowanie.

Abe Miessler
źródło
1
nie można użyć kompresji mniejszej niż kodowanie Huffmana !! Idealnie nadają się do tekstów ... ale po ich otrzymaniu powinieneś naprawdę wiedzieć o tej mutacji, którą zrobiłeś, aby odzyskać tekst.
6
Andy Smith
@Andrew - Ok, jakieś sugestie?
Abe Miessler,

Odpowiedzi:

30

Końcowe „=” lub „==” w Base64 jest tylko po to, aby liczba znaków była wielokrotnością 4. Możesz go usunąć, ponieważ zawsze możesz przywrócić go później. Zauważ, że Base64 jest tak zwany, ponieważ używa 64 różnych znaków. Wielkie litery, małe litery i cyfry to 62. Tak więc Base64 używa również „/” i „+”, które mogą, ale nie muszą pasować do twojego rachunku.

Ogólnie rzecz biorąc, jeśli chcesz zakodować dowolne sekwencje bajtów w znaki alfanumeryczne, niekoniecznie istnieje jakieś rozszerzenie długości, ponieważ istnieje 256 możliwych wartości dla bajtu i tylko 62 znaki alfanumeryczne. Czasami nazywa się to zasadą szufladki . Schemat kodowania musi mieć rozszerzenie średniej długości logarytmu 256 / log 62 = 1,344 (średnia dla wszystkich sekwencji bajtów); w przeciwnym razie oznacza to, że niektóre gołębie są gdzieś miażdżone na śmierć i nie odzyskasz ich bez uszkodzenia (co oznacza: dwa różne łańcuchy zakodowane w tym samym, więc dekodowanie nie może działać niezawodnie).

Jest całkiem możliwe, że twoje ciągi nie są dokładnie „sekwencjami jednakowo losowych bajtów”; twoje łańcuchy mają jakieś znaczenie, co oznacza, że ​​nie pojawi się jak najwięcej sekwencji bajtów, ponieważ są one bez znaczenia. Na tej podstawie możesz prawdopodobnie opracować schemat kodowania, który będzie miał krótsze rozszerzenie długości niż standardowy Base64 (lub Base62, jeśli chcesz trzymać się ścisłych znaków alfanumerycznych). Jest to bezstratna kompresja danych . Działa na jasno zdefiniowanym modelu probabilistycznym tego, co może pojawić się jako dane wejściowe.

Podsumowanie: generic schemat kodowania ciągów alfanumerycznych do sekwencji takich, które nie lub mało długość rozszerzenie kiedykolwiek nastąpi, nie może istnieć; jest to matematyczna niemożliwość. Specyficzny schemat dostosowane do rodzaju ciągu wejściowego można oczekiwać można prawdopodobnie istnieć (ale ponieważ nie powiedzieć, jaki rodzaj sznurka można napotkać, nikt nie może pomóc w tej sprawie).

Tom Leek
źródło
1
+1, doskonałe wyjaśnienie. Nie wiedziałem o =/ ==jest uzależniona od długości mającego być wielokrotnością 4. Może będę mógł obejść dla moich potrzeb
Abe Miessler
Pamiętaj, że zakłada to brak szuflad. Unicode ma dużo liter. Naprawdę potrzebujemy lepszego zrozumienia prawdziwego problemu.
MSalters 11.11.11
@Tom, jak obliczyłeś średni współczynnik wydłużenia długości za pomocą podziału dziennika? Oparty na schemacie w en.wikipedia.org/wiki/Base64 ma całkowicie intuicyjny sens, że do każdego niezakodowanego znaku potrzeba 4/3 znaków w Base64 do reprezentowania. Zastanawiam się, jak doszedłeś do tego samego wniosku z matematyki ... dzięki :)
Jonathan Lin
Moje złe, głupie pytanie. log (256) = 8 bitów, log (64) = 6 bitów, stąd stosunek wynosi 8/6 = 4/3 = 1,333 dla Base64. Twoje zdrowie.
Jonathan Lin
4

Ponowne kodowanie znaków jest zwykle wykonywane, gdy system odbiorczy nie może ich przetworzyć. Na przykład BASE64 reprezentuje dane przy użyciu 6 bitów (2 6 , a więc 64) znaków, które reprezentują dłuższe sekwencje danych (czasami pojawiające się „==” na końcu to dopełnienie do wyrównania). Wynika to z faktu, że plik obrazu w wiadomości e-mail może zawierać 0xFE, a serwer pocztowy będzie niezadowolony z przesyłania tego (lub innego tradycyjnie nie drukującego znaku).

Nie ma kodowania, które „zmniejsza rozmiar”. Kodowanie to tylko odwzorowanie bitów na znak, który reprezentują. To powiedziawszy, ASCII to 7-bitowy zestaw znaków (kodowanie), który często jest przechowywany w 8 bitach przestrzeni. Jeśli ograniczysz zakresy, które akceptujesz, możesz także usunąć znaki kontrolne.

Korzystanie z tej metody oznacza, że ​​musisz zapisywać rzeczy na poziomie bitów, a także gra trochę piekła z szybkością maszyny i instrukcjami, ponieważ wszystkie nowoczesne maszyny mają wyrównania, które są wielokrotnościami 8 bitów. Dlatego na przykład Unicode to UTF-8, UTF-16 i UTF-32.

Jeśli robisz to dla bezpieczeństwa (dlatego opublikowałeś go w Security.SE, prawda?), Po prostu odfiltruj rzeczy i przechowuj je normalnie. Jeśli robisz to, aby zaoszczędzić miejsce, zastanów się, czy cały dodatkowy kod i wolniejszy czas dostępu (ponieważ większość wpisów przekroczy granice adresów) jest warta oszczędności miejsca.

Do tego czasu to fragment kodu kursu CS, w którym musieliśmy przekonwertować ASCII z pamięci 8-bitowej na 7-bitową:

    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
Jeff Ferland
źródło
2

Możesz skompresować dane za pomocą np. Gzip, bzip2 lub lzma, a następnie uruchomić przez base64, aby ograniczyć używany zestaw znaków. Jest to korzystne tylko w przypadku większych ciągów setek bajtów lub więcej.

Antti Rytsölä
źródło
1

dlaczego nie użyć kompresji LZ? może to być przyzwoity sposób kompresji łańcucha, ale byłby bardziej wydajny w przypadku długich łańcuchów. Jak długi jest ciąg docelowy, który chcesz zakodować?

A.Rashad
źródło
Jak kompresja LZ ma się do gzip lub bzip2 wymienionych w sugestii attir?
NoChance 11.11.11
gzip jest oparty na kodowaniu LZ i Huffman. więcej na LZ en.wikipedia.org/wiki/LZ77
A.Rashad