Испытание на сжатие текста на английском языке без потерь [закрыто]


12

Вызов:

Ваша задача (если вы решите принять ее) состоит в том, чтобы сжать и распаковать « Полное собрание сочинений Уильяма Шекспира » объемом 5 МБ, как показано здесь: http://www.gutenberg.org/cache/epub/100/pg100.txt

(MD5: a810f89e9f8e213aebd06b9f8c5157d8)

Правила:

  • Вы должны принять вход через STDINи выход через STDOUT...
  • ... и вы должны предоставить идентичный распакованный результат для ввода.
    • (Это означает, что вы должны иметь возможность cat inpt.txt | ./cmprss | ./dcmpress | md5получить тот же MD5, что и выше.)
    • (Все, что через STDERR, должно быть отброшено.)
  • Вы должны использовать менее 2048 символов для общего исходного кода.
    • (Это не код-гольф. Вы не будучи забил на основе длины исходного кода. Это является просто правилом , чтобы держать вещи конечно.)
    • (Возьмите объединенную длину всего исходного кода, если вы его разбили.)
  • Вы должны быть в состоянии (теоретически) обрабатывать аналогичные текстовые вводы тоже.
    • (например , жесткое кодирование механизма , который только способен выводить предоставленный Шекспира ввод является неприемлемым.)
    • (Сжатый размер других документов не имеет значения - при условии, что распакованный результат идентичен альтернативному вводу.)
  • Вы можете использовать любой язык (и).
    • (например, не стесняйтесь сжимать, используя awkи распаковывать, используя java)
  • Вы можете написать две отдельные программы или комбинировать их с каким-либо «переключателем», как вам угодно.
    • (Должны быть четкие демонстрации того, как вызывать режимы сжатия и распаковки)
  • Вы не можете использовать какие-либо внешние команды (например, через 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
Почему шаблон? Собираетесь ли вы создать фрагмент стека, который зависит от него?
Питер Тейлор

2
Если нет ограничения по размеру кода, что мешает мне написать программу сжатия, которая печатает 0 байтов, и программу распаковки, которая жестко запрограммирована для печати всех произведений Шекспира?
Линн

4
Можно добавить правило, которое говорит, что код должен теоретически работать с другими входными данными, что решает проблему, указанную @Mauris.
kirbyfan64sos

Ответы:


5

Perl 5, 3651284

Просто простая словарная словарная схема. Анализирует частоту слова в корпусе и использует ее, чтобы определить, использовать ли один или два байта служебной информации на слово. Использует два специальных символа для байтов \ 0 и \ 1, так как они не отображаются в корпусе. Есть много других символов, которые можно использовать. Это не было сделано. Не делает никакой кодировки Хаффмана или любого другого джаза.

Сценарий сжатия 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.