实现bzip2的行程编码


14

背景

应用BWT(在Burrows,Wheeler和Back中看到)和MTF(在Move到可打印的ASCII front中看到)之后,bzip2压缩器应用了一种相当独特的游程长度编码形式。

定义

出于这一挑战的目的,我们将转换BRLE定义如下:

给定仅包含ASCII字符且代码点在0x20和0x7A之间的输入字符串s,请执行以下操作:

  1. 用单次出现的字符替换每次运行的相等字符,并在第一个字符之后存储重复次数。

  2. 使用双射基数2以及符号和和对字符首次出现后的重复次数进行编码。{}

    非负整数n被编码为字符串b k …b 0,使得n = 2 k i(b k)+ ... + 2 0 i(b 0,其中i({)= 1i(})= 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或其字符串反数的内置函数。

  • 可以使用以下内置函数

    • 只要重复次数未存储在双射基数2中,就计算字符串的RLE或RLD。

    • 执行任何形式的基本转换。

  • 如果您选择STDOUT输出,您的代码可能会打印尾随换行符。

  • 您的代码必须适用于1000个或更少的ASCII字符输入,范围从0x20到0x7A,再加上大括号(0x7B和0x7D)。

  • 如果输入中包含大括号,则可以假定将BRLE应用于字符串是有效的结果。

  • 适用标准代码高尔夫规则。以字节为单位的最短提交获胜。


为什么不允许内置函数?
MilkyWay19年

Answers:


4

CJam,50 48字节

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

感谢Dennis节省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.

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. 

而不是"{}"可以使用`H,请与CJam捆绑使用:)
Maltysen

@Jakube对不起,我很困惑。
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 {{{{{}}作为输入不是示例之一。你试过了吗?
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>

一些解释

BB2的数字n,使用0和1:(n+1).toString(2).slice(1)

BB2中的字符串为数字:to_number(“ 0b1” + string)-即,添加最左边的1个二进制数字并从二进制转换(并减少1,在此特定实例中不需要)。

正则表达式以查找任何字符,后跟{}/[^{}][{}]+/g

查找重复字符的正则表达式: /(.)\1*/g

在替换中使用该正则表达式,第一个参数是“重复的”字符(最终仅重复1次),第二个参数是总重复字符串,其长度是我需要在BB2中编码的数字已经增加了1

...然后放在一起...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.