Verlustfreie Textkomprimierung in englischer Sprache [geschlossen]

12

Herausforderung:

Ihre Herausforderung (sollten Sie sich dafür entscheiden, dies zu akzeptieren) besteht darin, die 5 MB großen " Complete Works of William Shakespeare " zu komprimieren und zu dekomprimieren, die Sie hier finden: http://www.gutenberg.org/cache/epub/100/pg100.txt

(MD5: a810f89e9f8e213aebd06b9f8c5157d8)

Regeln:

  • Sie müssen Eingabe über STDINund Ausgabe über STDOUT...
  • ... und Sie müssen ein identisches dekomprimiertes Ergebnis für die Eingabe bereitstellen.
    • (Das heißt , Sie müssen fähig sein, cat inpt.txt | ./cmprss | ./dcmpress | md5und erhalten die gleiche MD5 wie oben.)
    • (Alles über STDERRist zu verwerfen.)
  • Sie müssen weniger als 2048 Zeichen für Ihren gesamten Quellcode verwenden.
    • (Dies ist nicht Code-Golf. Sie sind nicht auf die Dauer des Source-Code erzielt werden. Dies ist war nur eine Regel endlichen Dinge zu halten.)
    • (Nehmen Sie die verkettete Länge des gesamten Quellcodes, wenn Sie ihn aufgeteilt haben.)
  • Sie müssen ähnliche Klartexteingaben (theoretisch) auch verarbeiten können.
    • (z. B. ist die harte Codierung eines Mechanismus, der nur die bereitgestellten Shakespeare- Eingaben ausgeben kann, nicht akzeptabel.)
    • (Die komprimierte Größe anderer Dokumente spielt keine Rolle - vorausgesetzt, das dekomprimierte Ergebnis stimmt mit der alternativen Eingabe überein.)
  • Sie können eine oder mehrere Sprachen auswählen.
    • (z. B. können Sie mit komprimieren awkund mit dekomprimieren java)
  • Sie können zwei separate Programme schreiben oder sie mit einer Art "Schalter" kombinieren, wie Sie möchten.
    • (Es muss klare Demonstrationen geben, wie sowohl der Komprimierungs- als auch der Dekomprimierungsmodus aufgerufen werden können.)
  • Sie können nicht alle externen Befehle (zB durch Verwendung exec()).
    • (Wenn Sie eine Shell-Sprache verwenden - Entschuldigung. Sie müssen sich mit den integrierten Funktionen begnügen. Sie können gerne eine "inakzeptable" Antwort posten, um sie weiterzugeben und Spaß zu haben - dies wird jedoch nicht beurteilt!) )
  • Sie können nicht alle eingebauten oder Bibliothek bereitgestellten Funktionen verwenden , die zuvor benannten Zweck einverstanden ist , ist zu komprimieren Daten (wie gz, usw.)
    • (Eine Änderung der Codierung wird in diesem Zusammenhang nicht als Komprimierung betrachtet. Hier kann ein gewisses Maß an Diskretion angewendet werden. Sie können die Akzeptanz Ihrer Lösung auch in der Einreichung diskutieren.)
  • Bitte versuchen Sie Spaß zu haben, wenn Sie teilnehmen möchten!

Alle guten Wettbewerbe haben eine objektive Definition des Gewinnens; ergo:

  • Sofern alle Regeln eingehalten werden, gewinnt die kleinste komprimierte Ausgabe (in STDOUTBytes).
    • (Melden Sie Ihre Ausgabe bitte per ./cmprss | wc -c)
  • Bei einem Unentschieden (identische Ausgabegrößen) gewinnt die Community mit den meisten Stimmen.
  • Im Falle einer zweiten Auslosung (identische Community-Upstimmen) wähle ich einen Gewinner, der auf einer völlig subjektiven Prüfung der Eleganz und des reinen Genies basiert. ;-)

Wie einreichen:

Bitte formatieren Sie Ihren Eintrag mit dieser Vorlage:

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

<description>  (Detail is encouraged!)

    <CODE...
    ...>

<run instructions>

Ich möchte Leser und Einsender ermutigen, sich durch Kommentare zu unterhalten - ich glaube, es gibt eine echte Chance für die Menschen, durch codegolf.stack zu lernen und bessere Programmierer zu werden.

Gewinnen:

Ich bin bald in den Ferien: Vielleicht (oder auch nicht) werde ich in den nächsten Wochen die Einreichungen überwachen und die Herausforderung am 19. September abschließen. Ich hoffe, dies bietet eine gute Gelegenheit zum Nachdenken und Einreichen - und zum positiven Austausch von Techniken und Ideen.

Wenn Sie durch Ihre Teilnahme (als Leser oder Einsender) etwas Neues gelernt haben, hinterlassen Sie bitte einen Kommentar zur Ermutigung.

wally
quelle
1
Sie sollten dies markieren code-challenge.
kirbyfan64sos
1
Ist die Eingabe als Funktionsargument zulässig? Beispiel: Eine Lösung in Sprachen wie JavaScript konnte nicht über die Befehlszeile AFAIK ausgeführt werden. In meinem Fall wäre es einfach viel einfacher, im Browser zu laufen.
ETHproductions
1
Warum die Vorlage? Wollen Sie ein Stack-Snippet erstellen, das davon abhängt?
Peter Taylor
2
Wenn es keine Beschränkung der Codegröße gibt, was hindert mich daran, ein Komprimierungsprogramm zu schreiben, das 0 Bytes druckt, und ein Dekomprimierungsprogramm, das hartcodiert ist, um die gesamten Werke von Shakespeare zu drucken?
Lynn
4
Es könnte eine Regel hinzugefügt werden, die besagt, dass der Code theoretisch mit anderen Eingaben funktionieren sollte , wodurch das Problem gelöst wird, auf das @Mauris hingewiesen hat.
kirbyfan64sos

Antworten:

5

Perl 5, 3651284

Nur ein einfaches wortbasiertes Wörterbuchschema. Analysiert die Worthäufigkeit des Korpus und verwendet diese, um zu bestimmen, ob ein oder zwei Bytes Overhead pro Wort verwendet werden sollen. Verwendet zwei spezielle Symbole für die Bytes \ 0 und \ 1, da diese nicht im Korpus erscheinen. Es gibt viele andere Symbole, die verwendet werden könnten. Dies wurde nicht gemacht. Tut keine Huffman-Codierung oder irgendeinen Jazz.

Komprimierungsskript 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;
    }
}

Dekomprimierungsskript 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;
    }
}

Ausführen mit:

perl shakespeare.pl < pg100.txt >pg100.txt.compressed
perl deshakespeare.pl <pg100.txt.compressed >pg100.txt.restored
diff pg100.txt pg100.txt.restored
Skibrianski
quelle