Jenis pengkodean apa yang dapat saya gunakan untuk membuat string lebih pendek?

13

Saya tertarik pada pengkodean string yang saya miliki dan saya ingin tahu jika ada jenis pengkodean yang dapat digunakan yang hanya akan menyertakan karakter alfa dan numerik dan lebih disukai mempersingkat jumlah karakter yang diperlukan untuk mewakili string.

Sejauh ini saya telah melihat menggunakan pengkodean Base64 untuk melakukan ini tetapi tampaknya membuat string saya lebih lama dan kadang-kadang termasuk ==yang ingin saya hindari. Contoh:

nama tes | 120101

menjadi

dGVzdCBuYW1lfDEyMDEwMQ ==

yang berlangsung dari 16 hingga 24 karakter dan termasuk non-alfanumerik.

Adakah yang tahu tentang jenis pengkodean berbeda yang dapat saya gunakan yang akan memenuhi persyaratan saya? Poin bonus jika itu dibangun ke dalam kerangka NET. Atau ada perpustakaan pihak ketiga yang akan melakukan pengkodean.

Abe Miessler
sumber
1
tidak dapat menggunakan kompresi yang lebih kecil seperti Huffman coding !! Mereka sangat cocok untuk teks ... tetapi kemudian pada bagian penerima Anda harus benar-benar tahu tentang mutasi ini yang telah Anda lakukan untuk mendapatkan kembali teks tersebut.
6
Anda menggambarkan kompresi, bukan penyandian
Andy Smith
@Andrew - Oke, ada saran?
Abe Miessler

Jawaban:

30

Final '=' atau '==' di Base64 ada hanya untuk membuat jumlah karakter kelipatan 4. Anda dapat menghapusnya, karena Anda selalu dapat mengembalikannya nanti. Perhatikan bahwa Base64 disebut demikian karena menggunakan 64 karakter berbeda. Huruf besar, huruf kecil, dan angka, itu 62. Jadi Base64 juga menggunakan '/' dan '+', yang mungkin cocok atau tidak sesuai dengan tagihan Anda.

Secara umum, jika Anda ingin menyandikan urutan byte yang berubah-ubah menjadi karakter alfanumerik, perlu ada beberapa ekstensi panjang di suatu tempat, karena ada 256 nilai yang mungkin untuk byte, dan hanya 62 karakter alfanumerik. Kadang-kadang disebut prinsip pigeonhole . Skema pengkodean harus memiliki ekstensi panjang rata-rata log faktor 256 / log 62 = 1.344 (rata-rata di atas semua urutan byte); jika tidak, itu berarti bahwa beberapa merpati dihancurkan sampai mati di suatu tempat dan Anda tidak akan mendapatkannya kembali tanpa kerusakan (yang berarti: dua string berbeda dikodekan menjadi sama, sehingga decoding tidak dapat bekerja dengan andal).

Sekarang, sangat mungkin bahwa string Anda tidak persis "urutan byte acak yang seragam"; string Anda memiliki beberapa makna yang berarti bahwa urutan byte yang paling mungkin tidak akan terjadi, karena tidak ada artinya. Atas dasar itu, Anda mungkin dapat menyusun skema pengkodean yang akan menyebabkan ekstensi yang lebih panjang dari Base64 generik (atau Base62 jika Anda harus tetap menggunakan karakter alfanumerik yang ketat). Ini adalah kompresi data lossless . Ini bekerja lebih dari model probabilistik yang jelas tentang apa yang dapat muncul sebagai input.

Ringkasan: a generik skema untuk encoding string ke urutan alfanumerik sehingga tidak ada atau ekstensi panjang sedikit yang pernah terjadi, tidak bisa eksis; ini adalah ketidakmungkinan matematis. Sebuah spesifik skema yang disesuaikan untuk jenis string input yang Anda harapkan mungkin bisa eksis (tapi karena Anda tidak tahu apa jenis string mungkin Anda hadapi, tidak ada yang bisa membantu Anda dalam hal ini).

Tom Leek
sumber
1
+1, penjelasan yang bagus. Saya tidak tahu tentang =/ ==terkait dengan panjang harus kelipatan 4. Saya mungkin bisa mengatasi ini untuk kebutuhan saya
Abe Miessler
Pikiran Anda, ini mengasumsikan kurangnya lubang dara. Unicode memiliki banyak surat. Kami benar-benar membutuhkan pemahaman yang lebih baik tentang masalah sebenarnya .
MSalters
@ Tom, bagaimana Anda menghitung faktor ekstensi panjang rata-rata menggunakan divisi log? Berdasarkan diagram di en.wikipedia.org/wiki/Base64, itu benar-benar masuk akal bahwa untuk setiap karakter yang tidak ter-enkripsi dibutuhkan 4/3 karakter dalam Base64 untuk diwakili. Hanya ingin tahu bagaimana Anda sampai pada kesimpulan yang sama dengan matematika ... terima kasih :)
Jonathan Lin
Pertanyaan buruk dan bodoh saya. log (256) = 8 bit, log (64) = 6 bit, maka rasionya adalah 8/6 = 4/3 = 1.333 untuk Base64. Bersulang.
Jonathan Lin
4

Pengodean ulang karakter umumnya dilakukan ketika sistem penerima tidak dapat memprosesnya. Sebagai contoh, BASE64 merepresentasikan data menggunakan 6 bit (2 6 , karenanya 64) karakter untuk mewakili urutan data yang lebih panjang ("==" yang terkadang muncul pada akhirnya adalah padding untuk penyelarasan). Ini karena file gambar Anda dalam email mungkin memiliki 0xFE di dalamnya dan server email Anda akan tidak senang mentransmisikannya (atau karakter tradisional yang tidak dicetak).

Tidak ada pengkodean yang "mengurangi ukuran." Pengkodean hanyalah pemetaan bit ke karakter yang diwakilinya. Yang mengatakan, ASCII adalah set karakter 7 bit (encoding) yang sering disimpan dalam ruang 8 bit. Jika Anda membatasi rentang yang Anda terima, Anda juga dapat menghilangkan karakter kontrol.

Menggunakan metode ini berarti Anda harus menulis hal-hal pada tingkat bit, dan juga memainkan sedikit neraka dengan kecepatan & instruksi mesin karena semua mesin modern memiliki keberpihakan yang merupakan kelipatan dari 8 bit. Misalnya, itulah sebabnya Unicode adalah UTF-8, UTF-16, dan UTF-32.

Jika Anda melakukan ini untuk keamanan (itu sebabnya Anda mempostingnya di Security.SE, kan?), Cukup filter dan simpan secara normal. Jika Anda melakukan ini untuk menghemat ruang, pertimbangkan apakah semua kode tambahan dan waktu akses lebih lambat (karena sebagian besar entri akan melewati batas alamat) sepadan dengan penghematan ruang.

Oleh, berikut ini adalah cuplikan dari kursus CS di mana kami harus mengubah ASCII dari penyimpanan 8 bit menjadi 7 bit:

    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
sumber
2

Anda dapat mengompres data dengan mis. Gzip, bzip2 atau lzma dan kemudian jalankan melalui base64 untuk membatasi set karakter yang digunakan. Ini bermanfaat hanya pada string yang lebih besar dari ratusan byte atau lebih.

Antti Rytsölä
sumber
1

mengapa tidak menggunakan kompresi LZ? ini bisa menjadi cara yang layak untuk mengompresi string, tetapi akan lebih efisien jika string panjang. Berapa lama string target yang ingin Anda encode?

A.Rashad
sumber
Bagaimana kompresi LZ dibandingkan dengan gzip atau bzip2 yang disebutkan dalam saran attir?
NoChance 11/11
gzip dibangun di atas LZ dan Huffman Coding. lebih lanjut tentang LZ en.wikipedia.org/wiki/LZ77
A.Rashad