bzip2のランレングスエンコーディングを実装する


14

バックグラウンド

BWT(Burrows、Wheeler、Backで見られる)とMTF(Move to the printable ASCII frontで見られる)を適用した後、bzip2コンプレッサーはかなりユニークな形式のランレングスエンコーディングを適用します。

定義

この課題のために、変換BRLEを次のように定義します。

0x20〜0x7Aのコードポイントを持つASCII文字のみで構成される入力文字列sを指定して、次の操作を行います。

  1. 等しい文字の各実行をその文字の1回の出現で置き換え、最初の文字以降の繰り返し回数を保存します。

  2. 繰り返し数を符号化文字の最初の発生の後に使用して、全単射ベース2記数や記号{などを}

    非負整数nは文字列として符号化されたB K ... B 0ように、N = 2 K I(BのK)+ ... + 2 0、I(B 0I({)= 1I(})= 2

    この表現は常に一意であることに注意してください。たとえば、数値0は空の文字列としてエンコードされます。

  3. 対応する文字が1回出現した後、繰り返し回数をエンコードする中括弧の文字列を挿入します。

ステップバイステップの例

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や文字列のその逆数を計算する任意のビルトインを使用します。

  • 次のビルトイン使用できます。

    • 繰り返し回数が全単射のbase-2に保存されていない限り、文字列のRLEまたはRLDを計算します。

    • あらゆる種類のベース変換を実行します。

  • 出力にSTDOUTを選択すると、コードが末尾の改行を出力する場合があります。

  • コードは、0x20から0x7Aの範囲の1000文字以下のASCII文字、および中括弧(0x7Bおよび0x7D)の入力に対して機能する必要があります。

  • 入力に中かっこが含まれている場合、BRLEを文字列に適用した有効な結果であると想定できます。

  • 標準コードのゴルフ規則が適用されます。バイト単位の最短提出が勝ちです。


ビルトインが許可されないのはなぜですか?
MilkyWay90

回答:


4

CJam、50 48バイト

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

2バイトを節約してくれたDennisに感謝します。

オンラインでお試しください。

説明

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.

3

Pyth、48 50バイト

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

@Maltysenのおかげで2バイト。

デモンストレーション。 テストハーネス。

説明:

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. 

代わりに、CJamと結び付けて"{}"使用できます`H:)
Maltysen

@ジャクベ混乱してごめんなさい。
isaacg

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

最初は、中括弧の存在を確認する必要があると考えていましたが、不要であることがわかりました。デコードは、すでにデコードされている文字列には明らかに影響を与えず、エンコード部分はすでにエンコードされている文字列と同様に無害であることが証明されました。


the encoding part proved equally harmlessしますか?エンコーディング4{{8{{{G{{{{W{{{{{は得られません4{{8{}G{{{W{{}か?
edc65

@ edc65いいえ、例で指定されている答えが得られます。どのようにテストしていますか?
feersum

「入力としての4 {{8 {{G {{{{W {{{{{」は例の1つではありません。試しましたか?
edc65

@ edc65これは例の1つの逆であり、私はそれらを両方の方法でテストしました。はい、投稿前とコメント後の両方で試しました。
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>

いくつかの説明

0および1を使用してBB2に番号n(n+1).toString(2).slice(1)

BB2の文字列から数値へ:to_number( "0b1" + string)-つまり、左端の1桁の2進数を追加し、2進数から変換します(この特定のインスタンスでは1ずつ減少します)。

任意の文字を見つけるための正規表現は続きます{}/[^{}][{}]+/g

繰り返される文字を見つけるための正規表現: /(.)\1*/g

交換にその正規表現を使用して、最初のパラメータは、第paramは、その長さIはBB2でエンコードする必要があること数である総繰り返し文字列であり、「繰り返し」チャーは(最終的にはわずか1時間の繰り返し)が既に1つインクリメント

...次にすべてをまとめます...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.