ความท้าทายในการบีบอัดข้อความภาษาอังกฤษแบบไม่สูญเสีย [ปิด]


12

ท้าทาย:

ความท้าทายของคุณ (หากคุณเลือกที่จะยอมรับ) คือการบีบอัดและขยายขนาด 5MB " Complete Works of William Shakespeare " ตามที่พบที่นี่: http://www.gutenberg.org/cache/epub/100/pg100.txt

(MD5: a810f89e9f8e213aebd06b9f8c5157d8)

กฎ:

  • คุณต้องป้อนข้อมูลผ่านSTDINและส่งออกผ่านSTDOUT...
  • ... และคุณต้องให้ผลลัพธ์ที่คลายการบีบอัดเหมือนกันกับอินพุต
    • (นี่คือการพูดว่าคุณจะต้องสามารถcat inpt.txt | ./cmprss | ./dcmpress | md5และรับMD5 เดียวกันข้างต้น)
    • (สิ่งใดที่ผ่านSTDERRจะถูกยกเลิก)
  • คุณต้องใช้อักขระน้อยกว่า 2048 ตัวสำหรับรหัสที่มาทั้งหมดของคุณ
    • (นี่ไม่ใช่ code-golf คุณไม่ได้รับคะแนนตามความยาวของซอร์สโค้ดนี่เป็นเพียงกฎเพื่อรักษาสิ่งที่ จำกัด )
    • (ใช้ความยาวที่ต่อกันของซอร์สโค้ดทั้งหมดหากคุณแยกออก)
  • คุณต้องสามารถประมวลผลอินพุตข้อความธรรมดาที่คล้ายกันได้ (ในทางทฤษฎี)
    • (เช่นการเข้ารหัสยากกลไกซึ่งเป็นเพียงความสามารถในการแสดงผลที่มีให้เช็คสเปียร์อินพุทเป็นที่ยอมรับ.)
    • (ขนาดที่บีบอัดของเอกสารอื่นไม่เกี่ยวข้อง - หากผลลัพธ์ที่คลายบีบอัดนั้นเหมือนกับอินพุตทางเลือก)
  • คุณสามารถใช้ภาษาใดก็ได้
    • (เช่นใช้การบีบอัดawkและคลายการบีบอัดjava)
  • คุณสามารถเขียนโปรแกรมสองโปรแกรมแยกกันหรือรวมเข้ากับ "switch" บางรูปแบบตามที่คุณต้องการ
    • (ต้องมีการสาธิตที่ชัดเจนถึงวิธีการเรียกใช้ทั้งโหมดบีบอัดและโหมดคลายบีบอัด)
  • คุณไม่สามารถใช้คำสั่งภายนอก (เช่นผ่านexec())
    • (ถ้าคุณใช้ภาษาของเชลล์ - ขอโทษคุณต้องทำกับบิวด์อินคุณสามารถโพสต์คำตอบ "ไม่เป็นที่ยอมรับ" เพื่อการแบ่งปันและความเพลิดเพลิน - แต่มันจะไม่ถูกตัดสิน! )
  • คุณไม่สามารถใช้ฟังก์ชั่นที่มีอยู่ในตัวหรือไลบรารีที่ระบุไว้ซึ่งมีวัตถุประสงค์เพื่อบีบอัดข้อมูล (เช่นgzและอื่น ๆ )
    • (การเปลี่ยนการเข้ารหัสไม่ถือว่าเป็นการบีบอัดในบริบทนี้อาจใช้ดุลยพินิจบางอย่างที่นี่โปรดอย่าลังเลที่จะยอมรับการยอมรับโซลูชันของคุณในการส่ง)
  • โปรดลองมีความสุขถ้าเลือกที่จะเข้าร่วม!

การแข่งขันที่ดีทั้งหมดมีคำจำกัดความวัตถุประสงค์ของการชนะ เพราะฉะนั้น:

  • กฎทั้งหมดจะถูกจัดเตรียมไว้ให้ซึ่งการบีบอัดที่เล็กที่สุด(เป็นSTDOUTไบต์) จะชนะ
    • (รายงานการส่งออกของคุณโปรดผ่าน./cmprss | wc -c)
  • ในกรณีที่มีการจับสลาก (ขนาดผลงานที่เหมือนกัน) ชุมชนที่ชนะการโหวตมากที่สุด
  • ในกรณีที่มีการจับสลากครั้งที่สอง (ชุมชนที่เหมือนกันได้รับการโหวต) ฉันจะเลือกผู้ชนะตามการตรวจสอบอัตนัยของความสง่างามและอัจฉริยะบริสุทธิ์ ;-)

วิธีการส่ง:

โปรดจัดรูปแบบรายการของคุณโดยใช้เทมเพลตนี้:

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

<description>  (Detail is encouraged!)

    <CODE...
    ...>

<run instructions>

ฉันจะสนับสนุนให้ผู้อ่านและผู้ส่งความคิดเห็นผ่านการสนทนา - ฉันเชื่อว่ามีโอกาสจริงที่ผู้คนจะเรียนรู้และกลายเป็นโปรแกรมเมอร์ที่ดีขึ้นผ่าน codegolf.stack

ชนะ:

ฉันจะไปพักผ่อนในวันหยุดเร็ว ๆ นี้: ฉันอาจจะ (หรืออาจจะไม่) กำลังตรวจสอบการส่งผลงานในอีกไม่กี่สัปดาห์ข้างหน้าและจะดึงความท้าทายไปสู่วันที่ 19 กันยายน ฉันหวังว่านี่จะเป็นโอกาสที่ดีสำหรับคนที่จะคิดและส่ง - และสำหรับการแบ่งปันเทคนิคและความคิดเชิงบวก

หากคุณได้เรียนรู้สิ่งใหม่จากการเข้าร่วม (ในฐานะผู้อ่านหรือผู้ส่ง) โปรดแสดงความคิดเห็นให้กำลังใจ


1
code-challengeคุณควรแท็กนี้
kirbyfan64sos

1
อนุญาตให้อินพุตเป็นอาร์กิวเมนต์ของฟังก์ชันหรือไม่ เช่นโซลูชันในภาษาเช่น JavaScript ไม่สามารถเรียกใช้จากบรรทัดคำสั่ง AFAIK ในกรณีของฉันมันจะง่ายกว่าที่จะทำงานในเบราว์เซอร์
ETHproductions

1
ทำไมต้องเป็นเทมเพลต คุณจะสร้างตัวอย่างสแต็กซึ่งขึ้นอยู่กับมันหรือไม่?
Peter Taylor

2
หากไม่มีการ จำกัด ขนาดรหัสฉันจะหยุดเขียนโปรแกรมบีบอัดที่พิมพ์ 0 ไบต์ได้อย่างไรและโปรแกรมคลายการบีบอัดที่เขียนโค้ดแบบยากที่จะพิมพ์งานทั้งหมดของ Shakespeare
ลินน์

4
สามารถเพิ่มกฎที่บอกว่ารหัสควรทำงานร่วมกับอินพุตอื่นในทางทฤษฎีซึ่งจะช่วยแก้ปัญหา @Mauris ได้
kirbyfan64sos

คำตอบ:


5

Perl 5, 3651284

เป็นเพียงรูปแบบพจนานุกรมคำง่ายๆ วิเคราะห์ความถี่ของคำศัพท์ของคลังข้อมูลและใช้เพื่อกำหนดว่าจะใช้หนึ่งหรือสองไบต์ของค่าใช้จ่ายต่อคำ ใช้สองสัญลักษณ์พิเศษสำหรับไบต์ \ 0 และ \ 1 เนื่องจากไม่ปรากฏในคลังข้อมูล มีสัญลักษณ์อื่น ๆ อีกมากมายที่สามารถใช้ได้ สิ่งนี้ไม่ได้ทำ ไม่ทำการเข้ารหัส huffman หรือแจ๊สใด ๆ

สคริปต์การบีบอัด 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;
    }
}

สคริปต์การบีบอัดข้อมูล 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;
    }
}

เรียกใช้โดยใช้:

perl shakespeare.pl < pg100.txt >pg100.txt.compressed
perl deshakespeare.pl <pg100.txt.compressed >pg100.txt.restored
diff pg100.txt pg100.txt.restored
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.