Che tipo di codifica posso usare per accorciare una stringa?


13

Sono interessato a codificare una stringa che ho e sono curioso di sapere se esiste un tipo di codifica che può essere utilizzato che includerà solo caratteri alfa e numerici e preferibilmente accorcerebbe il numero di caratteri necessari per rappresentare la stringa.

Finora ho cercato di usare la codifica Base64 per farlo, ma sembra allungare la mia stringa e talvolta include ==ciò che vorrei evitare. Esempio:

nome del test | 120101

diventa

dGVzdCBuYW1lfDEyMDEwMQ ==

che va da 16 a 24 caratteri e include non alfanumerici.

Qualcuno sa di un diverso tipo di codifica che potrei usare che soddisferà i miei requisiti? Punti bonus se è integrato nel framework .NET o esiste una libreria di terze parti che eseguirà la codifica.


1
non posso usare una perdita meno compressione come la codifica Huffman !! Sono ideali per i testi ... ma alla fine della ricezione dovresti davvero conoscere questa mutazione che hai fatto per recuperare il testo.

6
Stai descrivendo la compressione, non la codifica
Andy Smith l'

@Andrew - Ok, qualche suggerimento?
Abe Miessler,

Risposte:


30

L'ultimo '=' o '==' in Base64 è lì solo per rendere il numero di caratteri un multiplo di 4. Puoi rimuoverlo, poiché puoi sempre rimetterlo in seguito. Si noti che Base64 è così chiamato perché utilizza 64 caratteri distinti. Lettere maiuscole, lettere minuscole e cifre, questo è 62. Quindi Base64 usa anche '/' e '+', che possono o meno adattarsi al conto.

In generale, se si desidera codificare sequenze arbitrarie di byte in caratteri alfanumerici, esiste necessariamente un'estensione di lunghezza da qualche parte, perché ci sono 256 possibili valori per un byte e solo 62 caratteri alfanumerici. Talvolta viene chiamato principio del buco del piccione . Uno schema di codifica deve avere un'estensione di lunghezza media di un log fattoriale 256 / log 62 = 1.344 (media su tutte le sequenze di byte); altrimenti, significa che alcuni piccioni vengono schiacciati a morte da qualche parte e non li riavrai senza danni (il che significa: due stringhe distinte codificate nello stesso, quindi la decodifica non può funzionare in modo affidabile).

Ora, è del tutto possibile che le tue stringhe non siano esattamente "sequenze di byte uniformemente casuali"; le tue stringhe hanno un significato, il che significa che la maggior parte possibile di byte non si verificherà, perché sono insignificanti. Su questa base, probabilmente puoi escogitare uno schema di codifica che comporterà un'estensione della lunghezza inferiore rispetto al Base64 generico (o Base62 se devi attenerti a caratteri alfanumerici rigorosi). Questa è la compressione dei dati senza perdita di dati . Funziona su un modello probabilistico chiaramente definito di ciò che può apparire come input.

Riepilogo: non può esistere uno schema generico per codificare le stringhe in sequenze alfanumeriche in modo tale che non si verifichi mai l'estensione minima o minima; è un'impossibilità matematica. Uno schema specifico su misura per il tipo di stringa di input che ti aspetti può probabilmente esistere (ma poiché non dici quale tipo di stringa potresti incontrare, nessuno può aiutarti in questo).


1
+1, spiegazione eccellente. Non sapevo del =/ ==essere correlato alla lunghezza che doveva essere un multiplo di 4. Potrei essere in grado di aggirare questo per i miei bisogni
Abe Miessler,

Intendiamoci, questo presuppone una mancanza di buchi. Unicode ha molte lettere. Abbiamo davvero bisogno di una migliore comprensione del vero problema.
Salterio

@Tom come hai calcolato il fattore di estensione della lunghezza media usando la divisione log? Basato sul diagramma in en.wikipedia.org/wiki/Base64 ha perfettamente senso intuitivo che per ogni carattere non codificato siano necessari 4/3 caratteri in Base64 per rappresentare. Mi chiedo solo come sei arrivato alla stessa conclusione con la matematica ... grazie :)
Jonathan Lin

La mia brutta, stupida domanda. log (256) = 8 bit, log (64) = 6 bit, quindi il rapporto è 8/6 = 4/3 = 1.333 per Base64. Saluti.
Jonathan Lin,

4

La ricodifica dei caratteri viene generalmente eseguita quando il sistema ricevente non può elaborarli. Ad esempio, BASE64 rappresenta i dati utilizzando 6 bit (2 6 , quindi 64) di caratteri per rappresentare sequenze di dati più lunghe (il "==" alla fine che appare alla fine è il riempimento per l'allineamento). Questo perché il tuo file di immagine nell'e-mail potrebbe contenere 0xFE e il tuo server di posta non sarà contento di trasmetterlo (o qualsiasi altro carattere tradizionalmente non stampabile).

Non esiste una codifica che "riduce le dimensioni". Le codifiche sono solo mappature di bit sul carattere che rappresentano. Detto questo, ASCII è un set di caratteri a 7 bit (codifica) che viene spesso memorizzato in 8 bit di spazio. Se limiti gli intervalli che accetti, puoi anche eliminare i caratteri di controllo.

L'uso di questo metodo significa che devi scrivere le cose a livello di bit e gioca anche un po 'all'inferno con la velocità e le istruzioni della macchina perché tutte le macchine moderne hanno allineamenti multipli di 8 bit. Questo, ad esempio, è il motivo per cui Unicode è UTF-8, UTF-16 e UTF-32.

Se lo stai facendo per sicurezza (è per questo che l'hai pubblicato su Security.SE, giusto?), Basta filtrare le cose e archiviarle normalmente. Se lo stai facendo per risparmiare spazio, considera se tutto il codice extra e il tempo di accesso più lento (perché la maggior parte delle voci attraverseranno i confini degli indirizzi) valgono i risparmi di spazio.

A proposito, il seguente è un frammento di un corso CS in cui abbiamo dovuto convertire ASCII da 8 bit di archiviazione a 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

2

È possibile comprimere i dati con ad esempio gzip, bzip2 o lzma e quindi eseguire base64 per limitare il set di caratteri utilizzato. Questo è utile solo su stringhe più grandi di centinaia di byte o più.


1

perché non usare la compressione LZ? questo può essere un modo decente per comprimere una stringa, ma sarebbe più efficiente in caso di stringhe lunghe. Quanto dura la stringa target che vuoi codificare?


Come si confronta la compressione LZ con gzip o bzip2 menzionati nel suggerimento attir?
NoChance,

gzip è basato su LZ e Huffman Coding. altro su LZ en.wikipedia.org/wiki/LZ77
A.Rashad
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.