Lossless challenge di compressione del testo in lingua inglese [chiuso]


12

Sfida:

La tua sfida (se dovessi scegliere di accettarla) è quella di comprimere e decomprimere le " Complete Works of William Shakespeare " da 5 MB come trovate qui: http://www.gutenberg.org/cache/epub/100/pg100.txt

(MD5: a810f89e9f8e213aebd06b9f8c5157d8)

Regole:

  • È necessario prendere l'input via STDINe l'uscita via STDOUT...
  • ... e devi fornire un risultato decompresso identico all'input.
    • (Questo per dire che devi essere in grado di cat inpt.txt | ./cmprss | ./dcmpress | md5ottenere lo stesso MD5 di cui sopra.)
    • (Qualunque via STDERRdeve essere scartata.)
  • È necessario utilizzare meno di 2048 caratteri per il codice sorgente totale.
    • (Questo è non è il codice-golf. Stai non essere segnato base alla durata del codice sorgente. Questo è stato solo una regola per mantenere le cose finite.)
    • (Prendi la lunghezza concatenata di tutto il codice sorgente se lo hai diviso.)
  • È necessario essere in grado di ingressi solo testo (in teoria) di processo simile anche.
    • (ad esempio disco codifica un meccanismo che è solo in grado di emettere la condizione Shakespeare ingresso è inaccettabile.)
    • (La dimensione compressa di altri documenti è irrilevante, a condizione che il risultato decompresso sia identico all'input alternativo.)
  • È possibile utilizzare qualsiasi lingua o lingue.
    • (es. sentiti libero di comprimere usando awke decomprimere usando java)
  • Si può scrivere due programmi separati o combinarli con una qualche forma di "switch" come ti pare.
    • (Devono esserci chiare dimostrazioni su come invocare le modalità di compressione e decompressione)
  • Si può non utilizzare i comandi esterni (ad esempio attraverso exec()).
    • (Se stai usando un linguaggio shell - scusa. Dovrai accontentarti dei built-in. Ti invitiamo a pubblicare una risposta "inaccettabile" per motivi di condivisione e divertimento, ma non sarà giudicato! )
  • Si può non utilizzare alcuna funzione built-in o libreria fornita che ha dichiarato scopo è quello di comprimere i dati (come gz, ecc)
    • (Modificare la codifica non è considerato compressione in questo contesto. In questo caso può essere applicata una certa discrezione. Sentiti libero di sostenere l'accettabilità della tua soluzione nella presentazione.)
  • Prova a divertirti se scegli di partecipare!

Tutte le buone competizioni hanno una definizione obiettiva di vincita; quindi:

  • A condizione che tutte le regole vengano rispettate, l' output compresso più piccolo (in STDOUTbyte) vince.
    • (Segnala il tuo output per favore tramite ./cmprss | wc -c)
  • In caso di pareggio (dimensioni identiche dell'output), vince il maggior numero di voti positivi della community.
  • In caso di una seconda estrazione (voti identici della community), sceglierò un vincitore basato su un esame completamente soggettivo di eleganza e genio puro. ;-)

Come inviare:

Si prega di formattare la voce utilizzando questo modello:

<language>, <compressed_size>
-----------------------------

<description>  (Detail is encouraged!)

    <CODE...
    ...>

<run instructions>

Incoraggerei i lettori e i presentatori a conversare attraverso i commenti - credo che ci sia una reale opportunità per le persone di imparare e diventare programmatori migliori attraverso codegolf.stack.

Vincente:

Presto sarò in vacanza: potrei (o no) monitorare le presentazioni nelle prossime settimane e concluderà la sfida il 19 settembre. Spero che ciò offra una buona opportunità per le persone di pensare e presentare - e per una condivisione positiva di tecniche e idee.

Se hai imparato qualcosa di nuovo dalla partecipazione (come lettore o mittente), lascia un commento di incoraggiamento.


1
Dovresti etichettarlo code-challenge.
Kirbyfan64sos,

1
È consentito prendere l'input come argomento di funzione? Ad esempio, una soluzione in lingue come JavaScript non può essere eseguita dalla riga di comando, AFAIK. Nel mio caso, sarebbe semplicemente molto più semplice eseguirlo nel browser.
ETHproductions

1
Perché il modello? Stai per creare uno snippet di stack che dipende da esso?
Peter Taylor,

2
Se non esiste un limite di dimensione del codice, cosa mi impedisce di scrivere un programma comprimere che stampa 0 byte e un programma decomprimere che è hardcoded per stampare l'intero lavoro di Shakespeare?
Lynn,

4
Si potrebbe aggiungere una regola che dice che il codice dovrebbe teoricamente funzionare con altri input, risolvendo il problema sottolineato da @Mauris.
Kirbyfan64sos,

Risposte:


5

Perl 5, 3651284

Solo un semplice schema di dizionario basato su parole. Analizza la frequenza delle parole del corpus e la utilizza per determinare se utilizzare uno o due byte di overhead per parola. Utilizza due simboli speciali per i byte \ 0 e \ 1 poiché non compaiono nel corpus. Ci sono molti altri simboli che potrebbero essere usati. Questo non è stato fatto. Non esegue alcuna codifica huffman o quel jazz.

Script di compressione shakespeare.pl:

use strict;
use warnings;
use bytes;

my $text = join "", <>;
my @words = split/([^a-zA-Z0-9]+)/, $text;


my %charfreq;
for( my $i = 0; $i<length($text); ++$i ) {
    $charfreq{ substr($text, $i, 1) }++
}
for my $i ( 0..255 ) {
    my $c = chr($i);
    my $cnt = $charfreq{$c} // 0;
}



my %word_freq;
foreach my $word ( @words ) {
    $word_freq{ $word }++;
}


my $cnt = 0;
my ( @dict, %rdict );
foreach my $word ( sort { $word_freq{$b} <=> $word_freq{$a} || $b cmp $a } keys %word_freq ) {
    last if $word_freq{ $word } == 1; 


    my $repl_length = $cnt < 127 ? 2 : 3;
    if( length( $word ) > $repl_length ) {
        push @dict, $word;
        $rdict{ $word } = $cnt;
        $cnt++;
    }
}


foreach my $index ( 0..$
    print "$dict[$index]\0";
}
print "\1";


foreach my $word ( @words ) {
    my $index = $rdict{ $word };
    if ( defined $index && $index <= 127 ) {
        print "\0" . chr( $index );
    } elsif ( defined $index ) {
        my $byte1 = $index & 127;
        my $byte2 = $index >> 7;
        print "\1" . chr( $byte2 ) . chr( $byte1 );
    } else {
        print $word;
    }
}

Script di decompressione deshakespeare.pl:

use strict;
use warnings;
use bytes;

local $/;
my $compressed = <>;
my $text = $compressed;
$text =~ s/^.+?\x{1}//ms;
my $dictionary = $compressed;
$dictionary =~ s/\x{1}.*$//ms;


my $cnt = 0;
my @dict;
foreach my $word ( split "\0", $dictionary ) {

    push @dict, $word;
}


my @words = split /(\x{0}.|\x{1}..)/ms, $text;
foreach my $word ( @words ) {
    if( $word =~ /^\x{0}(.)/ms ) {
        print $dict[ ord( $1 ) ];
    } elsif( $word =~ /^\x{1}(.)(.)/ms ) {
        my $byte1 = ord( $1 );
        my $byte2 = ord( $2 );
        my $index = ( $byte1 << 7 ) + $byte2;
        print $dict[ $index ];
    } else {
        print $word;
    }
}

Esegui utilizzando:

perl shakespeare.pl < pg100.txt >pg100.txt.compressed
perl deshakespeare.pl <pg100.txt.compressed >pg100.txt.restored
diff pg100.txt pg100.txt.restored
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.