Défi de compression de texte en anglais sans perte [fermé]

12

Défi:

Votre défi (si vous l'acceptez) est de compresser et de décompresser les 5MB " Complete Works of William Shakespeare " comme ici: http://www.gutenberg.org/cache/epub/100/pg100.txt

(MD5: a810f89e9f8e213aebd06b9f8c5157d8)

Règles:

  • Vous devez prendre l'entrée via STDINet la sortie via STDOUT...
  • ... et vous devez fournir un résultat décompressé identique à l'entrée.
    • (Cela signifie que vous devez pouvoir cat inpt.txt | ./cmprss | ./dcmpress | md5obtenir le même MD5 que ci-dessus.)
    • (Tout via STDERRdoit être jeté.)
  • Vous devez utiliser moins de 2048 caractères pour votre code source total.
    • (C'est pas le code-golf. Vous ne sont notées en fonction de la longueur de code source. Il est était une règle de garder les choses finies.)
    • (Prenez la longueur concaténée de tout le code source si vous l'avez divisé.)
  • Vous devez également pouvoir (théoriquement) traiter des entrées en texte brut similaires.
    • (Par exemple, coder en dur un mécanisme qui est uniquement capable de produire l' entrée Shakespeare fournie est inacceptable.)
    • (La taille compressée des autres documents n'est pas pertinente - à condition que le résultat décompressé soit identique à l'entrée alternative.)
  • Vous pouvez utiliser n'importe quel choix de langue (s).
    • (par exemple, n'hésitez pas à compresser en utilisant awket décompresser en utilisant java)
  • Vous pouvez écrire deux programmes distincts ou les combiner avec une certaine forme de «commutateur» à votre guise.
    • (Il doit y avoir des démonstrations claires de la façon d'invoquer les modes de compression et de décompression)
  • Vous ne pouvez utiliser aucune commande externe (par exemple via exec()).
    • (Si vous utilisez un langage shell - désolé. Vous devrez vous contenter des fonctions intégrées. Vous êtes invités à publier une réponse "inacceptable" pour le partage et le plaisir - mais elle ne sera pas jugée! )
  • Vous ne pouvez pas utiliser les fonctions intégrées ou fournies par la bibliothèque dont le but déclaré est de compresser les données (comme gz, etc.)
    • (La modification du codage n'est pas considérée comme une compression dans ce contexte. Une certaine discrétion peut être appliquée ici. N'hésitez pas à faire valoir l'acceptabilité de votre solution dans la soumission.)
  • Veuillez essayer de vous amuser si vous décidez de participer!

Toutes les bonnes compétitions ont une définition objective de gagner; ergo:

  • Si toutes les règles sont respectées, la plus petite sortie compressée (en STDOUToctets) l'emporte.
    • (Signalez votre sortie via via ./cmprss | wc -c)
  • En cas d'égalité (tailles de sortie identiques), le plus de votes positifs de la communauté l'emporte.
  • Dans le cas d'un deuxième tirage (votes positifs de la communauté identique), je choisirai un gagnant basé sur un examen complètement subjectif de l'élégance et du génie pur. ;-)

Comment soumettre:

Veuillez formater votre entrée en utilisant ce modèle:

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

<description>  (Detail is encouraged!)

    <CODE...
    ...>

<run instructions>

J'encourage les lecteurs et les soumissionnaires à converser par le biais de commentaires - je pense qu'il existe de réelles opportunités pour les gens d'apprendre et de devenir de meilleurs programmeurs via codegolf.stack.

Gagnant:

Je pars bientôt en vacances: je surveillerai (ou non) les soumissions au cours des prochaines semaines et je mettrai un terme au défi le 19 septembre. J'espère que cela offre une bonne occasion pour les gens de réfléchir et de soumettre - et pour un partage positif des techniques et des idées.

Si vous avez appris quelque chose de nouveau en participant (en tant que lecteur ou soumissionnaire), veuillez laisser un commentaire d'encouragement.

wally
la source
1
Vous devez marquer cela code-challenge.
kirbyfan64sos
1
La prise de l'entrée comme argument de fonction est-elle autorisée? Par exemple, une solution dans des langages tels que JavaScript ne peut pas être exécutée à partir de la ligne de commande, AFAIK. Dans mon cas, il serait tout simplement beaucoup plus facile à exécuter dans le navigateur.
ETHproductions
1
Pourquoi le modèle? Allez-vous créer un extrait de pile qui en dépend?
Peter Taylor
2
S'il n'y a pas de limite de taille de code, qu'est-ce qui m'empêche d'écrire un programme de compression qui imprime 0 octet et un programme de décompression codé en dur pour imprimer l'ensemble des œuvres de Shakespeare?
Lynn
4
Une règle pourrait être ajoutée qui dit que le code devrait théoriquement fonctionner avec d'autres entrées, ce qui résout le problème signalé par @Mauris.
kirbyfan64sos

Réponses:

5

Perl 5, 3651284

Juste un schéma de dictionnaire simple basé sur des mots. Analyse la fréquence des mots du corpus et l'utilise pour déterminer s'il faut utiliser un ou deux octets de surcharge par mot. Utilise deux symboles spéciaux pour les octets \ 0 et \ 1 car ils n'apparaissent pas dans le corpus. Il existe de nombreux autres symboles qui pourraient être utilisés. Cela n'a pas été fait. Ne fait aucun encodage huffman ou tout ce jazz.

Script de compression 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 de décompression 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;
    }
}

Exécutez en utilisant:

perl shakespeare.pl < pg100.txt >pg100.txt.compressed
perl deshakespeare.pl <pg100.txt.compressed >pg100.txt.restored
diff pg100.txt pg100.txt.restored
skibrianski
la source