Реализовать кодировку длины прогона bzip2

14

Фон

После применения BWT (как показано в Burrows, Wheeler и Back ) и MTF (как видно в Move на лицевой стороне ASCII для печати ) компрессор bzip2 применяет довольно уникальную форму кодирования длин серий.

Определение

Для этой задачи мы определим преобразование BRLE следующим образом:

Учитывая входную строку s, которая состоит исключительно из символов ASCII с кодовыми точками от 0x20 до 0x7A, выполните следующее:

  1. Замените каждую серию одинаковых символов на одно вхождение символа и сохраните количество повторений после первого.

  2. Кодируйте количество повторений после первого вхождения символа , используя биективную нумерацию base-2 и символы {и }.

    Неотрицательное целое число n кодируется в виде строки b k … b 0 , так что n = 2 k i (b k ) +… + 2 0 i (b 0 ) , где i ( {) = 1 и i ( }) = 2 ,

    Обратите внимание, что это представление всегда уникально. Например, число 0 кодируется как пустая строка.

  3. Вставьте строку фигурных скобок, которая кодирует количество повторений после единственного вхождения соответствующего символа.

Пошаговый пример

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

задача

Реализуйте инволютивную программу или функцию, которая считывает одну строку из STDIN или в качестве аргумента командной строки или функции и печатает или возвращает либо BRLE, либо его инверсию входной строки.

Если ввод не содержит фигурных скобок, примените BRLE. Если входные данные содержат фигурные скобки, примените их в обратном порядке.

Примеры

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

Дополнительные правила

  • Вы не можете использовать любые встроенные модули, которые вычисляют BRLE или его инверсию строки.

  • Вы можете использовать встроенные модули, которые:

    • Вычислить RLE или RLD строки, если количество повторений не сохранено в bijective base-2.

    • Выполните базовое преобразование любого вида.

  • Ваш код может напечатать завершающий символ новой строки, если вы выберете STDOUT для вывода.

  • Ваш код должен работать для любого ввода 1000 или менее символов ASCII в диапазоне от 0x20 до 0x7A, плюс фигурные скобки (0x7B и 0x7D).

  • Если входные данные содержат фигурные скобки, вы можете предположить, что это правильный результат применения BRLE к строке.

  • Применяются стандартные правила игры в гольф. Самая короткая подача в байтах побеждает.

Деннис
источник
Почему встроенные функции не разрешены?
MilkyWay90

Ответы:

4

CJam, 50 48 байтов

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

Спасибо Денису за сохранение 2 байта.

Попробуйте онлайн.

объяснение

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
источник
3

Pyth, 48 50 байтов

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

2 байта благодаря @Maltysen.

Демонстрация. Тестовый жгут.

Объяснение:

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
источник
вместо "{}"тебя можно использовать `H, связанный с CJam :)
Maltysen
@Jakube Извините за путаницу.
Исаак
2

OCaml, 252

t это функция, которая выполняет преобразование.

#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

Сначала я думал, что должен проверить наличие фигурных скобок, но это оказалось ненужным. Декодирование явно не влияет на строки, которые уже декодированы, и часть кодирования оказалась одинаково безвредной для тех, которые уже были закодированы.

feersum
источник
the encoding part proved equally harmlessЯвляется ли? Кодировка 4{{8{{{G{{{{W{{{{{не получается 4{{8{}G{{{W{{}?
edc65
@ edc65 Нет, я получаю ответ, указанный в примерах. Как вы это тестируете?
feersum
"4 {{8 {{{G {{{{W {{{{{" "в качестве входных данных не является одним из примеров. Вы пробовали это?
edc65
@ edc65 Это инверсия одного из примеров, и я протестировал их в обоих направлениях. Да, я пробовал, как до публикации, так и после вашего комментария.
feersum
Хорошо. Я указал на цитируемое предложение, так как «прямолинейное» кодирование (как и мое) не было бы совершенно безвредным при данном тестовом примере. Очевидно, что ваша кодирующая часть более умна.
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>

Некоторое объяснение

Число n до BB2, используя 0 и 1:(n+1).toString(2).slice(1)

Строка в BB2 в число: to_number ("0b1" + строка) - то есть, добавьте крайнюю левую 1 двоичную цифру и преобразуйте из двоичной (и уменьшите на 1, в данном конкретном случае не требуется).

Регулярное выражение для поиска любого символа с последующим {или }:/[^{}][{}]+/g

Регулярное выражение для поиска повторяющихся символов: /(.)\1*/g

Используя это регулярное выражение вместо, первый параметр - это «повторный» символ (в конце концов, повторяется только 1 раз), второй параметр - это общая повторяющаяся строка, длина которой - это число, которое мне нужно кодировать в BB2, уже увеличенное на 1.

... тогда собрать все вместе ...

edc65
источник