Implemente la codificación de longitud de ejecución de bzip2

14

Antecedentes

Después de aplicar el BWT (como se ve en Burrows, Wheeler y Back ) y el MTF (como se ve en Mover al frente ASCII imprimible ), el compresor bzip2 aplica una forma bastante única de codificación de longitud de ejecución.

Definición

Para el propósito de este desafío, definimos la transformación BRLE de la siguiente manera:

Dada una cadena de entrada s que consiste únicamente en caracteres ASCII con puntos de código entre 0x20 y 0x7A, haga lo siguiente:

  1. Reemplace cada ejecución de caracteres iguales por una sola aparición del personaje y almacene el número de repeticiones después de la primera.

  2. Codifique el número de repeticiones después de la primera aparición del personaje , usando la numeración biyectiva base-2 y los símbolos {y }.

    Un número entero no negativo n se codifica como la cadena b k … b 0 de modo que n = 2 k i (b k ) +… + 2 0 i (b 0 ) , donde i ( {) = 1 e i ( }) = 2 .

    Tenga en cuenta que esta representación es siempre única. Por ejemplo, el número 0 está codificado como una cadena vacía.

  3. Inserte la cadena de llaves que codifica el número de repeticiones después de la aparición del carácter correspondiente.

Ejemplo paso a paso

Input:  "abbcccddddeeeeeffffffggggggghhhhhhhh"
Step 1: "abcdefgh" with repetitions 0, 1, 2, 3, 4, 5, 6, 7
Step 2: "" "{" "}" "{{" "{}" "}{" "}}" "{{{"
Step 3: "ab{c}d{{e{}f}{g}}h{{{"

Tarea

Implemente un programa o función involutiva que lea una sola cadena de STDIN o como argumento de línea de comando o función e imprima o devuelva el BRLE o su inverso de la cadena de entrada.

Si la entrada no contiene llaves, aplique el BRLE. Si la entrada contiene corchetes, aplique su inverso.

Ejemplos

INPUT:  CODEGOLF
OUTPUT: CODEGOLF

INPUT:  PROGRAMMING
OUTPUT: PROGRAM{ING

INPUT:  PUZ{LES
OUTPUT: PUZZLES

INPUT:  444488888888GGGGGGGGGGGGGGGGWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
OUTPUT: 4{{8{{{G{{{{W{{{{{

INPUT:  y}}}{{
OUTPUT: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

Reglas adicionales

  • No puede utilizar ninguna función integrada que calcule el BRLE o su inverso de una cadena.

  • Usted puede utilizar muebles empotrados que:

    • Calcule el RLE o RLD de una cadena, siempre que el número de repeticiones no esté almacenado en la base 2 de bijective.

    • Realizar conversión de base de cualquier tipo.

  • Su código puede imprimir una nueva línea final si elige STDOUT para la salida.

  • Su código tiene que funcionar para cualquier entrada de 1000 caracteres ASCII o menos en el rango de 0x20 a 0x7A, más llaves (0x7B y 0x7D).

  • Si la entrada contiene llaves, puede suponer que es un resultado válido de aplicar el BRLE a una cadena.

  • Se aplican las reglas estándar del código de golf. La presentación más corta en bytes gana.

Dennis
fuente
¿Por qué no están permitidos los builtins?
MilkyWay90

Respuestas:

4

CJam, 50 48 bytes

l_{}`:T&1${_T#)_(@a?)+}%{(\2b)*}%@e`{(2b1>Tf=}%?

Gracias por Dennis por guardar 2 bytes.

Pruébalo en línea.

Explicación

l_              e# Read and duplicate input.
{}`:T           e# T = "{}"
&               e# If the input has '{ or '}:
    1$          e# Input.
    {           e# For each character:
        _T#)    e# If it is '{ or '}:
            _(  e# Return 0 for '{ or 1 for '}.
            @a  e# Otherwise, convert the character itself to an array (string).
        ?
        )+      e# If it is a number, increment and append to the previous array.
                e# If it is a string with at least 1 character, do nothing.
    }%
    {(\         e# For each character and bijective base 2 number:
        2b)*    e# Repeat the character 1 + that many times.
    }%
                e# Else:
    @           e# Input.
    e`          e# Run-length encoding.
    {(          e# For each character and length:
        2b1>    e# Convert the length to base 2 and remove the first bit.
        Tf=     e# Map 0 to '{ and 1 to '}.
    }%
?               e# End if.
jimmy23013
fuente
3

Pyth, 48 50 bytes

J`Hs?m*hdi+1xLJtd2tczf-@zTJUz@Jzsm+ed@LJtjhd2rz8

2 bytes gracias a @Maltysen.

Demostración. Prueba de arnés.

Explicación:

J`Hs?m*hdi+1xLJtd2tczf-@zTJUz@Jzsm+ed@LJtjhd2rz8
                                                    Implicit: z = input()
                                                    H is empty dict.
J`H                                                 J = repr(H) = "{}"
   s                                                Print the concatenation of
    ?                        @Jz                    If z and J share any chars:
                     f     Uz                       Filter range(len(z))
                      -@zTJ                         On the absence of z[T] in J.
                   cz                               Chop z at these indices.
                                                    just before each non '{}'.
                  t                                 Remove empty initial piece.
     m*hd                                           Map to d[0] *
         i       2                                  the base 2 number                             
            xLJtd                                   index in J mapped over d[:-1]
          +1                                        with a 1 prepended.
                                             rz8    Otherwise, run len. encode z
                                 m                  map over (len, char)
                                         jhd2       Convert len to binary.
                                        t           Remove leading 1  
                                     @LJ            Map to element of J.
                                  +ed               Prepend char.
                                s                   Concatenate. 
isaacg
fuente
en lugar de "{}"que puedas usar `H, atado con CJam :)
Maltysen
@Jakube Perdón por la confusión.
isaacg
2

OCaml, 252

t es la función que hace la transformación.

#load"str.cma"open Str
let rec(!)=group_beginning and
g=function|1->""|x->(g(x/2)^[|"{";"}"|].(x mod 2))and($)i s=if g i=s then i else(i+1)$s and
t s=global_substitute(regexp"\(.\)\1*\([{}]*\)")(fun s->String.make(1$matched_group 2 s)s.[!1]^g(!2- !1))s

Al principio pensaba que tenía que verificar la presencia de llaves, pero resultó ser innecesario. La decodificación claramente no tiene efecto en las cadenas que ya están decodificadas, y la parte de codificación resultó igualmente inofensiva para las que ya estaban codificadas.

Feersum
fuente
the encoding part proved equally harmless¿lo hace? Codificación 4{{8{{{G{{{{W{{{{{no entiendes 4{{8{}G{{{W{{}?
edc65
@ edc65 No, obtengo la respuesta especificada en los ejemplos. ¿Cómo lo estás probando?
feersum
"4 {{8 {{{G {{{{W {{{{{" como entrada no es uno de los ejemplos. ¿Lo intentaste?
edc65
@ edc65 Es el inverso de uno de los ejemplos y los probé en ambos sentidos. Sí, lo intenté, tanto antes de publicar como después de tu comentario.
feersum
Bien. Señalé la frase citada, como una "codificación straightforward` (como la mía) no sería inofensiva para nada con el caso de prueba dado claramente su parte de codificación es más inteligente..
edc65
1

JavaScript ( ES6 ), 162

f=s=>
(t=s[R='replace'](/[^{}][{}]+/g,n=>n[0].repeat('0b'+n[R](/./g,c=>c!='{'|0))))==s
?s[R](/(.)\1*/g,(r,c)=>c+r.length.toString(2).slice(1)[R](/./g,c=>'{}'[c])):t

// TEST
out=x=>O.innerHTML += x + '\n';

test=s=>O.innerHTML = s+' -> '+f(s) +'\n\n' + O.innerHTML;

[['CODEGOLF','CODEGOLF']
,['PROGRAMMING','PROGRAM{ING']
,['PUZ{LES','PUZZLES']
,['444488888888GGGGGGGGGGGGGGGGWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW','4{{8{{{G{{{{W{{{{{']
,['y}}}{{','yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy']]
.forEach(v=>{
  w=f(v[0])  
  out('Test ' + (w==v[1]?'OK':'Fail')+'\nInput:    '+v[0]+'\nExpected: '+v[1]+'\nResult:   '+w)
})  
Your test: <input id=I style='width:300px'><button onclick='test(I.value)'>-></button>
<pre id=O></pre>

Alguna explicación

Número n a BB2 usando 0 y 1:(n+1).toString(2).slice(1)

Cadena en BB2 a número: to_number ("0b1" + cadena), es decir, agregue un dígito binario más a la izquierda y convierta de binario (y disminuya en 1, no es necesario en esta instancia específica).

Expresión regular para encontrar cualquier carácter seguido de {o }:/[^{}][{}]+/g

Expresión regular para encontrar caracteres repetidos: /(.)\1*/g

Usando ese regexp en replace, el primer parámetro es el carácter "repetido" (eventualmente se repite solo 1 vez), el segundo parámetro es la cadena repetida total, cuya longitud es el número que necesito codificar en BB2 ya incrementado en 1

... luego poner todo junto ...

edc65
fuente