Tantangan kompresi teks bahasa Inggris lossless [ditutup]

12

Tantangan:

Tantangan Anda (jika Anda memilih untuk menerimanya) adalah untuk mengompresi dan mendekompres 5MB " Complete Works of William Shakespeare " seperti yang ditemukan di sini: http://www.gutenberg.org/cache/epub/100/pg100.txt

(MD5: a810f89e9f8e213aebd06b9f8c5157d8)

Aturan:

  • Anda harus mengambil input via STDINdan output melalui STDOUT...
  • ... dan Anda harus memberikan hasil dekompresi yang identik ke input.
    • (Ini artinya Anda harus dapat cat inpt.txt | ./cmprss | ./dcmpress | md5dan mendapatkan MD5 yang sama seperti di atas.)
    • (Apa pun via STDERRharus dibuang.)
  • Anda harus menggunakan kurang dari 2048 karakter untuk total kode sumber Anda.
    • (Ini bukan kode-golf. Anda tidak sedang mencetak berdasarkan panjang source-code. Ini adalah hanya sebuah aturan untuk menjaga hal-hal yang terbatas.)
    • (Ambil panjang gabungan semua kode sumber jika Anda telah membaginya.)
  • Anda harus dapat (secara teoritis) memproses input teks biasa yang serupa juga.
    • (mis. pengkodean keras suatu mekanisme yang hanya mampu menghasilkan input Shakespeare yang disediakan tidak dapat diterima.)
    • (Ukuran terkompresi dari dokumen lain tidak relevan - asalkan hasil dekompresi identik dengan input alternatif.)
  • Anda dapat menggunakan pilihan bahasa apa pun.
    • (mis. merasa bebas untuk kompres menggunakan awkdan dekompresi menggunakan java)
  • Anda dapat menulis dua program terpisah atau menggabungkannya dengan beberapa bentuk "saklar" sesuka Anda.
    • (Harus ada demonstrasi yang jelas tentang cara menjalankan mode kompresi dan dekompresi)
  • Anda tidak boleh menggunakan perintah eksternal apa pun (misalnya melalui exec()).
    • (Jika Anda menggunakan bahasa shell - maaf. Anda harus puas dengan built-in. Anda dapat memposting jawaban "tidak dapat diterima" demi berbagi dan kesenangan - tetapi itu tidak akan dinilai! )
  • Anda tidak boleh menggunakan fungsi yang disediakan built-in atau pustaka siapa yang menyatakan tujuannya adalah untuk kompres data (seperti gz, dll)
    • (Mengubah pengkodean tidak dianggap sebagai kompresi dalam konteks ini. Beberapa kebijaksanaan mungkin diterapkan di sini. Jangan ragu untuk menyatakan penerimaan solusi Anda dalam pengiriman.)
  • Cobalah bersenang-senang jika memilih untuk berpartisipasi!

Semua kompetisi yang baik memiliki definisi objektif tentang kemenangan; jadi:

  • Asalkan semua aturan dipatuhi, output terkompresi terkecil (dalam STDOUTbyte) menang.
    • (Laporkan hasil Anda, harap melalui ./cmprss | wc -c)
  • Jika terjadi pengundian (ukuran output identik), sebagian besar komunitas yang terpilih akan menang.
  • Dalam hal pengundian kedua (pemungutan suara komunitas identik), saya akan memilih seorang pemenang berdasarkan pemeriksaan subjektif sepenuhnya keanggunan dan kejeniusan murni. ;-)

Cara mengirim:

Harap format entri Anda menggunakan templat ini:

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

<description>  (Detail is encouraged!)

    <CODE...
    ...>

<run instructions>

Saya akan mendorong pembaca dan submiter untuk berkomunikasi melalui komentar - Saya percaya ada peluang nyata bagi orang untuk belajar dan menjadi programmer yang lebih baik melalui codegolf.stack.

Kemenangan:

Saya akan segera berlibur: Saya mungkin (atau mungkin tidak) memantau pengiriman selama beberapa minggu ke depan dan akan mengakhiri tantangan pada tanggal 19 September. Saya harap ini menawarkan kesempatan baik bagi orang untuk berpikir dan tunduk - dan untuk berbagi teknik dan ide yang positif.

Jika Anda telah mempelajari sesuatu yang baru dari berpartisipasi (sebagai pembaca atau submitter), silakan tinggalkan komentar untuk memberi semangat.

wally
sumber
1
Anda harus menandai ini code-challenge.
kirbyfan64sos
1
Apakah mengambil input sebagai argumen fungsi diperbolehkan? Misalnya, solusi dalam bahasa seperti JavaScript tidak dapat dijalankan dari baris perintah, AFAIK. Dalam kasus saya, itu hanya akan jauh lebih mudah dijalankan di browser.
Produk ETH
1
Mengapa template? Apakah Anda akan membuat snipet tumpukan yang bergantung padanya?
Peter Taylor
2
Jika tidak ada batasan ukuran kode, apa yang membuat saya berhenti menulis program kompres yang mencetak 0 byte, dan program dekompresi yang dikodekan keras untuk mencetak seluruh karya Shakespeare?
Lynn
4
Sebuah aturan dapat ditambahkan yang mengatakan bahwa kode tersebut secara teoritis harus bekerja dengan input lain, yang memecahkan masalah yang ditunjukkan @Mauris.
kirbyfan64sos

Jawaban:

5

Perl 5, 3651284

Hanya skema kamus berbasis kata yang sederhana. Menganalisis frekuensi kata dari corpus, dan menggunakannya untuk menentukan apakah akan menggunakan satu atau dua byte overhead per kata. Menggunakan dua simbol khusus untuk byte \ 0 dan \ 1 karena tidak muncul di corpus. Ada banyak simbol lain yang bisa digunakan. Ini tidak dilakukan. Tidak melakukan encoding huffman atau jazz apa pun itu.

Script kompresi 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 dekompresi 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;
    }
}

Jalankan menggunakan:

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