Desafío de compresión de texto en inglés sin pérdida [cerrado]

12

Desafío:

Su desafío (si decide aceptarlo) es comprimir y descomprimir los 5MB " Obras completas de William Shakespeare " que se encuentran aquí: http://www.gutenberg.org/cache/epub/100/pg100.txt

(MD5: a810f89e9f8e213aebd06b9f8c5157d8)

Reglas:

  • Usted debe tomar la entrada a través STDINy salida a través de STDOUT...
  • ... y debe proporcionar un resultado descomprimido idéntico a la entrada.
    • (Esto significa que debe poder cat inpt.txt | ./cmprss | ./dcmpress | md5obtener el mismo MD5 que el anterior).
    • (Cualquier cosa a través de STDERRdebe ser descartada).
  • Usted debe utilizar menos de 2048 caracteres para su código fuente total.
    • (Esto no es un código de golf. No se te califica en función de la longitud del código fuente. Esto es solo una regla para mantener las cosas finitas).
    • (Tome la longitud concatenada de todo el código fuente si lo ha dividido).
  • También debe ser capaz (en teoría) de procesar entradas de texto sin formato similares.
    • (por ejemplo, la codificación dura de un mecanismo que solo es capaz de generar la entrada de Shakespeare proporcionada es inaceptable).
    • (El tamaño comprimido de otros documentos es irrelevante, siempre que el resultado descomprimido sea idéntico a la entrada alternativa).
  • Usted puede utilizar cualquier elección de idioma (s).
    • (por ejemplo, siéntase libre de comprimir usando awky descomprimir usando java)
  • Usted puede escribir dos programas separados o combinarlos con algún tipo de "cambio" a su gusto.
    • (Debe haber demostraciones claras de cómo invocar los modos de compresión y descompresión)
  • Es posible que no se utilice ningún comandos externos (por ejemplo a través exec()).
    • (Si está utilizando un lenguaje de shell, lo siento. Tendrá que conformarse con los elementos integrados. Le invitamos a publicar una respuesta "inaceptable" para compartir y disfrutar, ¡pero no se juzgará! )
  • Es posible que no se utiliza ninguna función proporcionados incorporados o biblioteca que está declararon objetivo es comprimir los datos (como gz, etc)
    • (La alteración de la codificación no se considera compresión en este contexto. Puede aplicarse alguna discreción aquí. Siéntase libre de argumentar la aceptabilidad de su solución en el envío).
  • ¡Intenta divertirte si eliges participar!

Todas las buenas competiciones tienen una definición objetiva de ganar; es decir:

  • Siempre que se cumplan todas las reglas, la salida comprimida más pequeña (en STDOUTbytes) gana.
    • (Informe su salida por favor a través de ./cmprss | wc -c)
  • En caso de empate (tamaños de salida idénticos), la mayoría de los votos votados por la comunidad gana.
  • En caso de un segundo sorteo (votos positivos de la comunidad idénticos), elegiré un ganador basado en un examen completamente subjetivo de elegancia y genio puro. ;-)

Cómo enviar:

Formatee su entrada usando esta plantilla:

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

<description>  (Detail is encouraged!)

    <CODE...
    ...>

<run instructions>

Animaría a los lectores y a los que envían a conversar a través de comentarios: creo que hay una oportunidad real para que las personas aprendan y se conviertan en mejores programadores a través de codegolf.stack.

Victorioso:

Me voy de vacaciones pronto: puedo (o no) estar monitoreando los envíos durante las próximas semanas y cerraré el desafío el 19 de septiembre. Espero que esto ofrezca una buena oportunidad para que las personas piensen y presenten, y para un intercambio positivo de técnicas e ideas.

Si ha aprendido algo nuevo al participar (como lector o presentador), deje un comentario de aliento.

criajo
fuente
1
Deberías etiquetar esto code-challenge.
kirbyfan64sos
1
¿Está permitido tomar la entrada como argumento de función? Por ejemplo, una solución en lenguajes como JavaScript no se puede ejecutar desde la línea de comandos, AFAIK. En mi caso, simplemente sería mucho más fácil ejecutarlo en el navegador.
ETHproductions
1
¿Por qué la plantilla? ¿Vas a crear un fragmento de pila que depende de él?
Peter Taylor
2
Si no hay un límite de tamaño de código, ¿qué me impide escribir un programa de compresión que imprima 0 bytes y un programa de descompresión codificado para imprimir todos los trabajos de Shakespeare?
Lynn
44
Se podría agregar una regla que diga que el código debería funcionar teóricamente con otras entradas, lo que resuelve el problema que señaló @Mauris.
kirbyfan64sos

Respuestas:

5

Perl 5, 3651284

Solo un simple esquema de diccionario basado en palabras. Analiza la frecuencia de palabras del corpus y la usa para determinar si se deben usar uno o dos bytes de sobrecarga por palabra. Utiliza dos símbolos especiales para los bytes \ 0 y \ 1 ya que no aparecen en el corpus. Hay muchos otros símbolos que podrían usarse. Esto no fue hecho. No hace ninguna codificación huffman ni nada de ese jazz.

Script de compresión 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 descompresión 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;
    }
}

Ejecutar usando:

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