Implementar a codificação de comprimento de execução do bzip2

14

fundo

Depois de aplicar o BWT (como visto em Burrows, Wheeler e Back ) e o MTF (como visto em Mover para a frente ASCII imprimível ), o compressor bzip2 aplica uma forma bastante única de codificação de execução.

Definição

Para o objetivo deste desafio, definimos a transformação BRLE da seguinte forma:

Dada uma sequência de entrada s que consiste apenas em caracteres ASCII com pontos de código entre 0x20 e 0x7A, faça o seguinte:

  1. Substitua cada execução de caracteres iguais por uma única ocorrência do caractere e armazene o número de repetições após o primeiro.

  2. Codifique o número de repetições após a primeira ocorrência do caractere , usando a numeração bijetiva de base 2 e os símbolos {e }.

    Um número inteiro não negativo n é codificado como a cadeia b k … b 0, de modo que n = 2 k i (b k ) +… + 2 0 i (b 0 ) , onde i ( {) = 1 e i ( }) = 2 .

    Observe que essa representação é sempre única. Por exemplo, o número 0 é codificado como uma sequência vazia.

  3. Insira a sequência de colchetes que codifica o número de repetições após a ocorrência única do caractere correspondente.

Exemplo passo a passo

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{{{"

Tarefa

Implemente um programa ou função involutivo que leia uma única cadeia de caracteres de STDIN ou como argumento de linha de comando ou função e imprima ou retorne o BRLE ou seu inverso da cadeia de entrada.

Se a entrada não contiver colchetes, aplique o BRLE. Se a entrada contiver colchetes, aplique seu inverso.

Exemplos

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

Regras adicionais

  • Você não pode usar nenhum componente interno que calcule o BRLE ou o inverso de uma sequência.

  • Você pode usar built-ins que:

    • Calcule o RLE ou o RLD de uma sequência, desde que o número de repetições não seja armazenado na base bijetiva-2.

    • Realize a conversão básica de qualquer tipo.

  • Seu código pode imprimir uma nova linha à direita se você escolher STDOUT para saída.

  • Seu código precisa funcionar para qualquer entrada de 1000 caracteres ASCII ou menos no intervalo de 0x20 a 0x7A, além de colchetes (0x7B e 0x7D).

  • Se a entrada contiver colchetes, você pode assumir que é um resultado válido da aplicação do BRLE a uma string.

  • Aplicam-se regras de código padrão de golfe. O menor envio em bytes vence.

Dennis
fonte
Por que os buildins não são permitidos?
MilkyWay90

Respostas:

4

CJam, 50 48 bytes

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

Obrigado por Dennis por salvar 2 bytes.

Experimente online.

Explicação

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
fonte
3

Pitão, 48 50 bytes

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

2 bytes graças a @Maltysen.

Demonstração. Equipamento de teste.

Explicação:

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
fonte
em vez de "{}"você pode usar `H, amarrado com CJam :)
Maltysen
@Jakube Desculpe pela confusão.
Isaacg
2

OCaml, 252

t é a função que faz a transformação.

#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

No começo, eu pensava que tinha que verificar a presença de suspensórios, mas acabou sendo desnecessário. A decodificação claramente não tem efeito nas seqüências de caracteres que já foram decodificadas, e a parte de codificação se mostrou igualmente inofensiva para as que já foram codificadas.

feersum
fonte
the encoding part proved equally harmlessfaz isso? Codificação 4{{8{{{G{{{{W{{{{{você não entende 4{{8{}G{{{W{{}?
Edc65
@ edc65 Não, recebo a resposta especificada nos exemplos. Como você está testando?
feersum
"4 {{8 {{G {{{W {{{{{" "como entrada não é um dos exemplos. Você tentou?
Edc65
@ edc65 É o inverso de um dos exemplos e eu os testei nos dois sentidos. Sim, eu tentei, antes de postar e depois do seu comentário.
feersum
Tudo bem. Eu indiquei a frase citada, como um "encoding straightforward` (como a minha) não seria inofensiva em tudo com o dado caso de teste Claramente sua parte de codificação é mais 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>

Alguma explicação

Numere n a BB2 usando 0 e 1:(n+1).toString(2).slice(1)

Seqüência no BB2 para número: to_number ("0b1" + string) - ou seja, adicione um dígito binário mais à esquerda e converta do binário (e diminua 1, não necessário nesta instância específica).

Expressão regular para encontrar qualquer caractere seguido por {ou }:/[^{}][{}]+/g

Expressão regular para encontrar caracteres repetidos: /(.)\1*/g

Usando esse regexp em replace, o primeiro param é o caractere "repetido" (eventualmente repete apenas uma vez), o segundo param é a string total repetida, cujo comprimento é o número que eu preciso codificar no BB2 já incrementado por 1

... então junte tudo ...

edc65
fonte