以n为底的数字的ASCII艺术解压缩


24

这是受Magic Octupus Urn05AB1E答案的启发。

给定两个参数,一个正整数和一个字符串/字符列表:

  1. 将数字转换为base-n,其中n是字符串的长度。
  2. 对于每个字符,用该字符替换基数为n的该字符索引的所有出现。
  3. 打印或返回新字符串。

例子:

Input:
2740, ["|","_"]
2740 -> 101010110100 in base 2
     -> Replace 0s with "|" and 1s with "_"
Output: _|_|_|__|_||

Input:
698911, ["c","h","a","o"]
698911 ->  2222220133 in base 4
       ->  Replace 0s with "c", 1s with "h", 2s with "a", and 3s with "o"
Output -> "aaaaaachoo"

Input:
1928149325670647244912100789213626616560861130859431492905908574660758972167966, [" ","\n","|","_","-"]
Output:
    __   __    
   |  |_|  |   
___|       |___
-   -   -   -  
 - - - - - - - 
- - - - - - - -
_______________

Input: 3446503265645381015412, [':', '\n', '.', '_', '=', ' ', ')', '(', ',']
Output:
_===_
(.,.)
( : )
( : )

规则:

  • IO是灵活的
    • 您可以将数字取任意基数,只要输入之间的数字一致即可
    • 字符列表必须为0索引,其中0是第一个字符,n-1是最后一个字符
  • 可能的字符可以是任何可打印的ASCII,以及空格(例如制表符和换行符)
  • 给定的字符列表的长度将在2-10包括在内的范围内。也就是说,最小的底数是二进制的,最大的底数是十进制的(这里没有讨厌的字母
  • 禁止出现标准漏洞
  • 即使您的语言无法处理较大的测试用例,也可以随时回答。

因为这是,所以每种语言的最短代码胜出。(我知道你们所有的高尔夫语言都有一个字节的内置内置组件可供使用;)


沙盒(已删除)
Jo King

3
D'awwh,我感到很荣幸。05AB1E ascii-art是我前一段时间最喜欢的艺术
魔术章鱼缸

您可以提出一个新的挑战:在数组中查找字符的排列以最小化数字:)
mazzy

Answers:


8

05AB1E7 6 字节

gв¹sèJ

由于它受05AB1E答案的启发,因此05AB1E中给出的答案似乎很合适。:)

-1字节感谢@Enigma,它删除了foreach并隐式执行了此操作。

在线尝试验证所有测试用例

说明:

g         # `l`: Take the length of the first (string) input
 в        # And then take the second input in base `l`
          # For each digit `y` of this base-converted number:
  ¹sè     #  Push the `y`'th character of the first input
     J    # Join everything together (and output implicitly)

1
gв¹sèJ保存一个字节。
Emigna

@Emigna谢谢。不敢相信我现在还没有考虑过¹sè自己。.(我知道在这种情况下?将a 更改为a J会得到相同的输出。)
Kevin Cruijssen

6

Java 8,72 50字节

a->n->n.toString(a.length).chars().map(c->a[c-48])

-22字节的感谢@OlivierGrégoire通过返回a IntStream而不是直接打印来获得。

在线尝试

说明:

a->n->                  // Method with char-array and BigInteger parameters
  n.toString(a.length)  //  Convert the input-number to Base `amount_of_characters`
   .chars()             //  Loop over it's digits (as characters)
   .map(c->a[c          //   Convert each character to the `i`'th character of the input
              -48])     //   by first converting the digit-character to index-integer `i`

2
a->n->n.toString(a.length).chars().map(c->a[c-48])(50个字节),因为“ IO灵活”
OlivierGrégoire18年

String f(char[]a,int n){return n>0?f(a,n/a.length)+a[n%a.length]:"";}(69字节)递归之一,很有趣。
奥利维尔·格雷戈尔(OlivierGrégoire),

6

Python 3 3,49个字节

还无法发表评论,因此我发布了适用于Python 3.5的Python 2答案。

f=lambda n,s:n and f(n//len(s),s)+s[n%len(s)]or''

2
欢迎来到PPCG!随时包含一个TIO链接以帮助展示您的解决方案。
Jo King

5

Japt,2个字节

可以将第二个输入作为数组或字符串。由于数字超过JavaScript的最大整数,因此最后两个测试用例失败。替换sì输出字符数组代替。

sV

试试吧


5

Haskell40 39字节

0!_=[]
n!l=cycle l!!n:div n(length l)!l

在线尝试!

由于Haskell的Int类型仅限于9223372036854775807,因此对于较大的数字将失败。

-1字节感谢Laikoni

不打高尔夫球

(!) :: Int -> [Char] -> [Char]

0 ! _ = []  -- If the number is 0, we reached the end. Base case: empty string
n ! l = 
  let newN = (n `div` length l) in   -- divide n by the base
    cycle l!!n                       -- return the char encoded by the LSD ... 
    : newN!l                         -- ... prepended to the rest of the output (computed recursively)

在线尝试!


好主意cycle代替moddiv n(length l)保存一个字节。
Laikoni

4

MATL,2个字节

YA

在线尝试!

输入是数字和字符串。

2^53由于浮点精度,导致超过的数字失败。

说明

YA知道的是内置的(具有指定目标符号的基本转换)。


4

JavaScript(ES6),48个字节

以currying语法接受输入(c)(n),其中c是字符列表,n是整数。

仅对于n <2 53是安全的

c=>n=>n.toString(c.length).replace(/./g,i=>c[i])

在线尝试!


JavaScript(ES6),99个字节

支持大整数

采用currying语法输入(c)(a),其中c是字符列表,a是十进制数字列表(整数)。

c=>g=(a,p=0,b=c.length,r=0)=>1/a[p]?g(a.map((d,i)=>(r=d+r*10,d=r/b|0,r%=b,d|i-p||p++,d)),p)+c[r]:''

在线尝试!


4

x86 32位机器代码(32位整数):17个字节。

(另请参见下面的其他版本,包括16字节的32位或64位,以及DF = 1调用约定。)

调用者在寄存器中传递args,包括指向输出缓冲区末尾的指针(如我的C答案;有关算法的合理性和解释,请参阅它。) glibc内部_itoa执行此操作,因此,它不仅仅是为代码高尔夫而设计的。传递参数的寄存器与x86-64 System V接近,除了在EAX中有一个arg而不是EDX。

返回时,EDI指向输出缓冲区中0终止的C字符串的第一个字节。通常的返回值寄存器是EAX / RAX,但是在汇编语言中,您可以使用函数方便的任何调用约定。(xchg eax,edi最后将增加1个字节)。

呼叫者可以根据需要计算出明确的长度buffer_end - edi。但是我认为我们不能证明省略终止符是有道理的,除非函数实际上返回了两个开始+结束指针或两个指针+长度。在此版本中,这将节省3个字节,但我认为这是没有道理的。

  • EAX = n =要解码的数字。(对于idiv。其他args不是隐式操作数。)
  • EDI =输出缓冲区的末尾(64位版本仍在使用dec edi,因此必须在低4GiB中)
  • ESI / RSI =查找表,又名LUT。不被破坏
  • ECX =表的长度=基数。不被破坏

nasm -felf32 ascii-compress-base.asm -l /dev/stdout | cut -b -30,$((30+10))- (手工编辑以缩小注释,行号很奇怪。)

   32-bit: 17 bytes        ;  64-bit: 18 bytes
                           ; same source assembles as 32 or 64-bit
 3                         %ifidn __OUTPUT_FORMAT__, elf32
 5                         %define rdi edi
 6   address               %define rsi esi
11          machine        %endif
14          code           %define DEF(funcname) funcname: global funcname
16          bytes           
22                         ;;; returns: pointer in RDI to the start of a 0-terminated string
24                         ;;; clobbers:; EDX (tmp remainder)
25                         DEF(ascii_compress_nostring)
27 00000000 C60700             mov     BYTE [rdi], 0
28                         .loop:                    ; do{
29 00000003 99                 cdq                    ; 1 byte shorter than   xor edx,edx / div
30 00000004 F7F9               idiv    ecx            ; edx=n%B   eax=n/B
31                         
32 00000006 8A1416             mov     dl, [rsi + rdx]   ; dl = LUT[n%B]
33 00000009 4F                 dec     edi               ; --output  ; 2B in x86-64
34 0000000A 8817               mov     [rdi], dl         ; *output = dl
35                         
36 0000000C 85C0               test    eax,eax           ; div/idiv don't write flags in practice, and the manual says they're undefined.
37 0000000E 75F3               jnz     .loop         ; }while(n);
38                         
39 00000010 C3                 ret
           0x11 bytes = 17
40 00000011 11             .size: db $ - .start

令人惊讶的是,基本没有速度/大小折衷的最简单版本是最小的,但是std/ cld花费2个字节以stosb降序使用并仍然遵循常见的DF = 0调用约定。(并且STOS 存储递减,在循环退出时指针指向一个字节太低,这使我们浪费了额外的字节来解决。)

版本:

我提出了4种截然不同的实现技巧(使用简单的mov加载/存储(上述),使用lea/ movsb(整齐但不是最佳选择),使用xchg/ xlatb/ stosb/ xchg,以及一种通过重叠指令破解进入循环的方法。请参见下面的代码) 。最后一个需要0在查找表中尾随以复制为输出字符串终止符,因此我将其计为+1字节。取决于32/64位(是否为1字节inc)以及是否可以假定调用方设置DF = 1(stosb降序)或其他任何值,不同的版本(并列)最短。

DF = 1以降序存储使它成为xchg / stosb / xchg的胜利,但是调用者通常不希望这样做。感觉就像以一种难以辩解的方式将工作分担给呼叫者。(与自定义arg传递和返回值寄存器不同,自定义arg-passing和返回值寄存器通常不会花费asm调用程序任何额外的工作。)但是在64位代码中,cld/ scasb用作inc rdi,避免将输出指针截断为32位,因此有时不方便在64位清除函数中保留DF = 1。。(在Linux上的x86-64非PIE可执行文件中,静态代码/数据的指针是32位的,并且在Linux x32 ABI中始终如此,因此在某些情况下,可以使用使用32位指针的x86-64版本。)这种交互使得查看需求的不同组合变得很有趣。

  • 具有DF = 0的IA32进入/退出调用约定:17B(nostring
  • IA32:16B(使用DF = 1约定:stosb_edx_argskew;或使用传入的DF = dontcare,将其设置为:16 + 1Bstosb_decode_overlap或17Bstosb_edx_arg
  • x86-64,带有64位指针,进入/退出调用约定为DF = 0:17 + 1字节(stosb_decode_overlap,18B(stosb_edx_argskew
  • 带有64位指针的x86-64,其他DF处理:16B(DF = 1 skew和17B(nostring对于DF = 1,使用scasb代替dec)。18B(stosb_edx_arg使用3个字节保留DF = 1 inc rdi)。

    或者,如果我们允许将指针返回到字符串15B之前的1个字节(末尾stosb_edx_arg不带inc)。 全部设置为再次调用,然后将另一个字符串扩展到具有不同基数/表的缓冲区中…… 但是如果我们不存储任何终止符0,那将更有意义,并且您可以将函数体放入循环中,这实际上是单独的问题。

  • 具有32位输出指针,DF = 0调用约定的x86-64:与64位输出指针相比没有任何改进,但nostring现在绑定了18B()。

  • 具有32位输出指针的x86-64:与最佳的64位指针版本相比没有任何改进,因此为16B(DF = 1 skew)。或设置DF = 1并将其保留为17B skewstd但不设置cld。或17 + 1B,stosb_decode_overlap以/ inc edi代替cld/ scasb

使用DF = 1调用约定:16个字节(IA32或x86-64)

在输入上需要DF = 1,保持设置不变。 至少在每项功能的基础上勉强合理。执行与上述版本相同的操作,但使用xchg可以在XLATB(以R / EBX为基础的表查找)和STOSB(*output-- = al)之前/之后将剩余部分输入AL中。

随着对入口/出口惯例正常DF = 0,所述std/ cld/ scasb版本是32位和64位代码18个字节,是64位的清洁(作品具有64位输出指针)。

请注意,输入args位于不同的寄存器中,包括表的RBX(用于xlatb)。另请注意,此循环从存储AL开始,以尚未存储的最后一个字符结束(因此mov在末尾)。因此,该循环相对于其他循环是“偏斜的”,因此得名。

                            ;DF=1 version.  Uncomment std/cld for DF=0
                            ;32-bit and 64-bit: 16B
157                         DEF(ascii_compress_skew)
158                         ;;; inputs
159                             ;; O in RDI = end of output buffer
160                             ;; I in RBX = lookup table  for xlatb
161                             ;; n in EDX = number to decode
162                             ;; B in ECX = length of table = modulus
163                         ;;; returns: pointer in RDI to the start of a 0-terminated string
164                         ;;; clobbers:; EDX=0, EAX=last char
165                         .start:
166                         ;    std
167 00000060 31C0               xor    eax,eax
168                         .loop:                    ; do{
169 00000062 AA                 stosb
170 00000063 92                 xchg    eax, edx
171                         
172 00000064 99                 cdq                    ; 1 byte shorter than   xor edx,edx / div
173 00000065 F7F9               idiv    ecx            ; edx=n%B   eax=n/B
174                         
175 00000067 92                 xchg    eax, edx       ; eax=n%B   edx=n/B
176 00000068 D7                 xlatb                  ; al = byte [rbx + al]
177                         
178 00000069 85D2               test    edx,edx
179 0000006B 75F5               jnz     .loop         ; }while(n = n/B);
180                         
181 0000006D 8807               mov     [rdi], al     ; stosb would move RDI away
182                         ;    cld
183 0000006F C3                 ret

184 00000070 10             .size: db $ - .start

一个类似的不偏斜版本会超出EDI / RDI,然后对其进行修复。

                            ; 32-bit DF=1: 16B    64-bit: 17B (or 18B for DF=0)
70                         DEF(ascii_compress_stosb_edx_arg)  ; x86-64 SysV arg passing, but returns in RDI
71                             ;; O in RDI = end of output buffer
72                             ;; I in RBX = lookup table  for xlatb
73                             ;; n in EDX = number to decode
74                             ;; B in ECX = length of table
75                         ;;; clobbers EAX,EDX, preserves DF
76                             ; 32-bit mode: a DF=1 convention would save 2B (use inc edi instead of cld/scasb)
77                             ; 32-bit mode: call-clobbered DF would save 1B (still need STD, but INC EDI saves 1)
79                         .start:
80 00000040 31C0               xor     eax,eax
81                         ;    std
82 00000042 AA                 stosb
83                         .loop:
84 00000043 92                 xchg    eax, edx
85 00000044 99                 cdq
86 00000045 F7F9               idiv    ecx            ; edx=n%B   eax=n/B
87                         
88 00000047 92                 xchg    eax, edx       ; eax=n%B   edx=n/B
89 00000048 D7                 xlatb                  ; al = byte [rbx + al]
90 00000049 AA                 stosb                  ; *output-- = al
91                         
92 0000004A 85D2               test    edx,edx
93 0000004C 75F5               jnz     .loop
94                         
95 0000004E 47                 inc    edi
96                             ;; cld
97                             ;; scasb          ; rdi++
98 0000004F C3                 ret
99 00000050 10             .size: db $ - .start
    16 bytes for the 32-bit DF=1 version

我尝试使用lea esi, [rbx+rdx]/ movsb作为内循环主体的替代版本 。(每次迭代都会重置RSI,但RDI会递减)。但是它不能使用xor-zero / stos作为终止符,因此它大了1个字节。(对于LEA上没有REX前缀的查找表,它不是64位清除的。)


具有明确长度 0终止符的LUT :16 + 1个字节(32位)

此版本设置DF = 1并保持原来的状态。我正在计算作为总字节数一部分所需的额外LUT字节。

这里很酷的技巧是使相同的字节以两种不同的方式解码。我们使用剩下的= base和商=输入数落入循环的中间,然后将0终止符复制到位。

第一次通过该函数时,循环的前3个字节被用作LEA的disp32的高字节。LEA将基数(模数)复制到EDX,idiv产生其余部分供以后的迭代。

idiv ebpis 的第二个字节FD,它是std此函数需要工作的指令的操作码。(这是一个幸运的发现。我一直在寻找这与div早些时候,从区别自己idiv使用/r的ModRM位。的第2个字节div epb解码为cmc,这是无害的,但没有帮助的。但随着idiv ebp我们能不能取出std从顶部功能)。

请注意,输入寄存器再次有所不同:EBP为基数。

103                         DEF(ascii_compress_stosb_decode_overlap)
104                         ;;; inputs
105                             ;; n in EAX = number to decode
106                             ;; O in RDI = end of output buffer
107                             ;; I in RBX = lookup table, 0-terminated.  (first iter copies LUT[base] as output terminator)
108                             ;; B in EBP = base = length of table
109                         ;;; returns: pointer in RDI to the start of a 0-terminated string
110                         ;;; clobbers: EDX (=0), EAX,  DF
111                             ;; Or a DF=1 convention allows idiv ecx (STC).  Or we could put xchg after stos and not run IDIV's modRM
112                         .start:
117                             ;2nd byte of div ebx = repz.  edx=repnz.
118                             ;            div ebp = cmc.   ecx=int1 = icebp (hardware-debug trap)
119                             ;2nd byte of idiv ebp = std = 0xfd.  ecx=stc
125                         
126                             ;lea    edx, [dword 0 + ebp]
127 00000040 8D9500             db  0x8d, 0x95, 0   ; opcode, modrm, 0 for lea edx, [rbp+disp32].  low byte = 0 so DL = BPL+0 = base
128                             ; skips xchg, cdq, and idiv.
129                             ; decode starts with the 2nd byte of idiv ebp, which decodes as the STD we need
130                         .loop:
131 00000043 92                 xchg    eax, edx
132 00000044 99                 cdq
133 00000045 F7FD               idiv    ebp            ; edx=n%B   eax=n/B;
134                             ;; on loop entry, 2nd byte of idiv ebp runs as STD.  n in EAX, like after idiv.  base in edx (fake remainder)
135                         
136 00000047 92                 xchg    eax, edx       ; eax=n%B   edx=n/B
137 00000048 D7                 xlatb                  ; al = byte [rbx + al]
138                         .do_stos:
139 00000049 AA                 stosb                  ; *output-- = al
140                         
141 0000004A 85D2               test    edx,edx
142 0000004C 75F5               jnz     .loop
143                         
144                         %ifidn __OUTPUT_FORMAT__, elf32
145 0000004E 47                 inc     edi         ; saves a byte in 32-bit.  Makes DF call-clobbered instead of normal DF=0
146                         %else
147                             cld
148                             scasb          ; rdi++
149                         %endif
150                         
151 0000004F C3                 ret
152 00000050 10             .size: db $ - .start
153 00000051 01                     db 1   ; +1 because we require an extra LUT byte
       # 16+1 bytes for a 32-bit version.
       # 17+1 bytes for a 64-bit version that ends with DF=0

这种重叠的解码技巧也可以与 cmp eax, imm32:仅花费1个字节就可以有效地向前跳4个字节,而只是破坏标志。(这对于在L1i高速缓存BTW中标记指令边界的CPU的性能非常糟糕。)

但是在这里,我们使用3个字节来复制寄存器并跳入循环。这通常需要2 + 2(mov + jmp),并且让我们直接在STOS之前而不是XLATB之前进入循环。但是然后我们需要一个单独的STD,这不会很有趣。

在线尝试!(与_start调用者一起使用sys_write结果)

最好通过调试在下运行它strace,或将输出十六进制转储,这样您可以查看是否\0在正确的位置有一个终结器,依此类推。但是您可以看到这确实有效,并产生AAAAAACHOO

num  equ 698911
table:  db "CHAO"
%endif
    tablen equ $ - table
    db 0  ; "terminator" needed by ascii_compress_stosb_decode_overlap

(实际上xxAAAAAACHOO\0x\0\0...,因为我们将缓冲区中的2个字节之前的数据转储到固定长度。所以我们可以看到该函数写入了应有的字节,并且没有踩到不应有的字节。)传递给函数的起始指针是倒数第二个x字符,后跟零。)


3

果冻,4字节

ṙ1ṃ@

在线尝试!

实际上是为此内置的。其他三个字节构成了Jelly基于索引的索引。


出于好奇,为什么Jelly甚至具有内置的基本解压缩;将x转换为基本长度(y),然后索引为y ”?是在非常特殊的情况下,您要转换为的基数与字符串/整数/列表的长度相等吗?当我搜索它时,我只能使用它找到三个答案:12 ; 3。Kinda在每天的代码高尔夫球中都有一个怪异的内置挑战imo。:S
Kevin Cruijssen

3
@KevinCruijssen,例如,当您想使用十六进制字母(而不是数字列表)将N转换为十六进制时,它非常有用。
Xcoder先生18年

@KevinCruijssen这是字符串的压缩方法。在第一个示例中,所需的字符串是“sspspdspdspfdspfdsp”,但是“çƥ÷£ḟ’ṃ“spdf”¤节省了六个字节。这对于Jelly的基数250尤其有用
dylnan

3

Python 2中49 48个字节

-1字节感谢Jo King

f=lambda n,s:n and f(n/len(s),s)+s[n%len(s)]or''

在线尝试!

替代版本(无法完成大量操作),45 43字节

-2个字节,感谢Jo King

f=lambda n,s:s*n and f(n/len(s),s)+(s*n)[n]

在线尝试!


3

木炭3 1字节

θη

在线尝试!链接是详细版本的代码。编辑:由于仅@ASCII,节省了2个字节。添加内置函数之前的先前版本,8字节:

⭆↨θLη§ηι

在线尝试!链接是详细版本的代码。说明:

    η       Second input
   L        Length
  θ         First input
 ↨          Base convert to array
⭆           Map over values and join
      η     Second input
       ι    Current value
     §      Index into list
            Implicitly print result

实际上,它应该已经可以工作了,但是显然我又搞砸了> _>
ASCII

另外,它实际上是1个字节:P(虽然目前已损坏,所以我不使用数字和字符串数组作为参数)(而且,我想知道隐式输入的使用方式(())有用)
仅ASCII的

仅@ASCII仅表示“ 1个字节”(请参阅​​-vl输出;-)。此外,隐式输入在Charcoal中似乎几乎没有用,除了类似的挑战。
尼尔

1
Neil的意思是仅@ASCII的复数“字节”而不是单数“字节”。;)至于您的1字节答案,为什么要划掉θη?看起来有点令人困惑。为什么不将其完全删除然后离开呢?
凯文·克鲁伊森

1
我仔细检查了@Nit,并在问问题之前添加了内置函数,但是我没有意识到,因为它有一个错误。
尼尔

3

D,112字节

import std.conv;C u(C,I)(I n,C b){C t;for(I l=b.length;n;n/=l)t=to!C(n%l)~t;foreach(ref c;t)c=b[c-48];return t;}

在线尝试!

这是一个港口 HatsuPointerKun的C ++答案

调用样式为u(ulong(n), to!(char[])(b)),其中nb是左右参数

D特定的东西

可悲的是,我们需要导入std.conv以进行非常以上的任何类型转换基本的类型转换类型转换。

使用golfy模板系统,并给予功能所需要的类型(这就是为什么称它不只是u(n,b)),我们可以缩短的出现char[],并ulong1字节每一个,里面的时候F中的功能。

D为我们初始化我们的类型,所以D的C t;缩写C t=cast(char[])([])

to!C将整数n%l转换为字符数组(使用代码点),并~进行级联

foreach(ref c;t)就像C ++的for(... : ...)循环一样,但是要更长一些。ref就像一样&,将其视为c按引用复制(即,我们可以修改t)。幸运的是,D推断类型,c而没有任何关键字表示类型。



3

C ++,150个 144字节,uint64输入

-6个字节,感谢Zacharý

#include<string>
using s=std::string;s u(uint64_t n,s b){s t;for(;n;n/=b.size())t=std::to_string(n%b.size())+t;for(auto&a:t)a=b[a-48];return t;}

使用变量存储大小将使字节数增加1

调用函数:

u(2740, "|_")

第一个是数字,第二个是字符串(char数组)

测试用例 :

std::cout << u(2740, "|_") << '\n' << u(698911, "chao") << '\n';
return 0;

1
3个字节剃掉:你不需要的空间后#include,你可以改变;;,只是;,并且'0'可以只是48
扎卡里

1
此外,while循环可能是一个for循环:for(;n;n/=b.size())t=std::to_string(n%b.size())+t;
扎卡里

@ceilingcat,我忘记了b.size()在那个循环中没有改变。
扎卡里

@ceilingcat会将字节数增加1,而不是减少
字节数

2

小枝,66字节

创建了一个macro必须import编辑到模板中的。

{%macro d(n,c)%}{%for N in n|split%}{{c[N]}}{%endfor%}{%endmacro%}

预期值:

对于第一个参数(n):

对于第二个参数(c):

  • 数字数组
  • 字符串数组

如何使用:

  • 创建一个 .twig档案
  • {% import 'file.twig' as uncompress %}
  • 调用宏 uncompress.d()

非高尔夫(非功能性):

{% macro d(numbers, chars) %}
    {% for number in numbers|split %}
        {{ chars[number] }}
    {% endfor %}
{% endmacro %}


您可以在以下位置测试此代码:https : //twigfiddle.com/54a0i9


2

Pyth,9 8 7字节

s@LQjEl

多亏了hakr14,节省了一个字节,多亏了Xcoder先生,节省了一个字节。
在这里尝试

说明

s@LQjEl
    jElQ      Convert the second input (the number) to the appropriate base.
 @LQ          Look up each digit in the list of strings.
s             Add them all together.

m@Qd@LQ
hakr14 '18

替换vz为保存一个字节E
Xcoder先生18年

2

C89,有限范围带符号int n64 53字节

  • changelog:获取char **out并修改它,而不是获取并返回achar *

将数字作为int,将查询表作为数组+长度。
输出写入char *outbuf。调用者(通过引用)传递一个指向缓冲区末尾的指针。函数修改该指针,使其在返回时指向字符串的第一个字节。

g(n,I,B,O)char*I,**O;{for(**O=0;n;n/=B)*--*O=I[n%B];}

这是有效的C89,即使启用了优化也可以正常工作。即不依赖于GCC-O0当非空函数结束或具有任何其他UB时行为。

对于优化的int-> string函数,例如glibc的internal_itoa,将指针传递到缓冲区的末尾是正常。请参阅此答案,以获取在C以及x86-64 asm中使用div / mod循环将整数分解为数字的详细说明。如果基数是2的幂,则可以先移位/屏蔽以提取MSD位,否则,唯一的好选择是首先提取最低有效位(取模)。

在线尝试!。非高尔夫版本:

/* int n = the number
 * int B = size of I = base
 * char I[] = input table
 * char **O = input/output arg passed by ref:
 *    on entry: pointer to the last byte of output buffer.
 *    on exit:  pointer to the first byte of the 0-terminated string in output buffer
 */
void ungolfed_g(n,I,B,O)char*I,**O;
{
    char *outpos = *O;     /* Golfed version uses *O everywhere we use outpos */
    *outpos = 0;           /* terminate the output string */
    for(;n;n/=B)
        *--outpos = I[n%B]; /* produce 1 char at a time, decrementing the output pointer */
    *O = outpos;
}

在这个明确的长版,输入的是char table[]它不没有需要终止0字节,因为我们从来没有把它作为一个字符串。这可能是int table[]我们所关心的。C没有知道自己长度的容器,因此,pointer + length是传递带有大小的数组的常规方法。所以我们选择它而不是需要strlen

最大缓冲区大小约为sizeof(int)*CHAR_BIT + 1,因此它很小且编译时常数。(我们在base = 2且所有位都设置为1的情况下使用了很大的空间。)例如33个字节用于32位整数,包括0终止符。


C89,带符号的int表,为隐式长度的C字符串,65字节

B;f(n,I,O)char*I,**O;{B=strlen(I);for(**O=0;n;n/=B)*--*O=I[n%B];}

这是同一件事,但是输入是一个隐式长度的字符串,因此我们必须自己找到长度。


2

Bash +核心实用程序,49字节

dc -e`echo -en $2|wc -c`o$1p|tr -dc 0-9|tr 0-9 $2

在线尝试!

评论/说明

这将命令行参数作为输入(以10为底的数字,然后是带有字符列表的单个字符串)作为输入,并输出到stdout。特殊字符,如空格,新行,等可以在八进制表示法输入(例如,\040用于空间),或\n为一个新行,\t对选项卡,或任何其他转义序列echo -etr相同的解释。

这里的许多字节用于处理特殊字符和较大的测试用例。如果我只需要处理不可怕的字符并且数字很小(例如,第一个测试用例),则以下24个字节可以做到:

dc -e${#2}o$1p|tr 0-9 $2

这使用参数扩展 ${#2}来获取字符串中的字符数,构建一个dc程序进行基本转换,然后将转换后的数字通过tr

但是,这不会处理换行符,空格或制表符,因此要在不影响基数的情况下处理转义序列,请wc -c在用解释转义后进行字符计数echo -en。这会将程序扩展为38个字节:

dc -e`echo -en $2|wc -c`o$1p|tr 0-9 $2

不幸的是,dc具有令人讨厌的“功能”,如果它输出大量数字,它将以斜杠+换行符序列对其进行换行,因此较大的测试用例具有此额外输出。要删除它,我通过管道传递dc的输出tr -dc 0-9以删除非数字字符。我们到了。


我打算建议dc -e${#2}o$1p|tr 0-9 "$2"直接输入而不是使用\ escaped形式,以便它可以处理空格,但是tr没有-例如不将其视为范围字符的选项。如果输入-不在字符串的一端,则它将中断。也许您可以使用sed "y/0123456789/$2/"。不,我想不是,GNU sed要求两个arg y的长度都相同,并且似乎在换行符上出现阻塞。
彼得·科德斯

2

APL(Dyalog Unicode)14 13 12字节

⊢⌷⍨∘⊂⊥⍣¯1⍨∘≢

在线尝试!

中缀默认功能;由于浮点表示,因此无法处理最大的测试用例。

感谢@Adám,节省了1 2字节!

标头添加了13个字节⎕IO←0::I dex O rigin = 0和⎕FR←1287F浮动R表示 = 128位。(我忘记了这并不适用。

怎么样?

⊢⌷⍨∘⊂⊥⍣¯1⍨∘≢    Tacit function, infix.
               Tally (number of elements in) the right argument.
         ⍨∘     Then swap the arguments of
     ⊥⍣¯1       Base conversion (to base ≢<r_arg>)
               Enclose (convert to an array)
  ⍨∘            Then swap the arguments of
               Index
               (Into) the right argument.

2

附件,17字节

{_[_2&ToBase!#_]}

在线尝试!

说明

{_[_2&ToBase!#_]}
{               }  ?? anonymous lambda; input: _ = dictionary, _2 = encoded
   _2&ToBase       ?? convert _2 to base
            !#_    ?? ... Size[_]
 _[            ]   ?? and take those members from the dictionary

1

画布,7 个字节

L┬{╵⁸@p

在这里尝试!

直接实施:

L┬{╵⁸@p
L      get the length of the input (popping the item)
 ┬     base decode the other input
  {    for each number there
   ╵     increment
    ⁸@   in the 1st input get that numbered item
      p  and output that

输入字符集也可以是字符串,只要它不包含换行符即可,因为Canvas没有换行符并自动将其转换为2D对象。


1

Stax6 5个字节

n%|E@

运行并调试

说明:

n%|E@ Full program, implicit input in order list, number
n%    Copy the list to the top and get its length
  |E  Convert the number to that base
    @ Map: index

1

SOGL V0.12,10 个字节

l;A─{IaWp}

在这里尝试!

很长一段时间,考虑到这个想法几乎是用语言实现的:在这里,输入

¶    __   __    ¶   |  |_|  |   ¶___|       |___¶-   -   -   -  ¶ - - - - - - - ¶- - - - - - - -¶_______________¶

使用此方法给出一个压缩字符串。



1

Stax,2个字节

:B

运行并调试

:B是在stax中执行此操作的指令。通常,它将对“字符串” *而不是“字符串”数组进行操作。最后,这意味着输出是单个字符数组的数组。但是无论如何,输出隐式趋于平坦。

* Stax实际上没有字符串类型。文本由代码点的整数数组表示。


never,我从没注意到这个命令……
wastl

有很多。我曾经在stax中添加一条已经存在的指令,而我只是忘记了。(数组是否降序?)
递归

1

J,12个字节

]{~#@]#.inv[

怎么样?

      #.inv    convert
           [   the left argument (the number)      
   #@]         to base the length of the right argument (the list of characters)    
  {~           and use the digits as indices to
]              the list of characters        

在线尝试!



1

C (gcc), 110 bytes

char s[99],S[99];i;f(x,_)char*_;{i=strlen(_);*s=*S=0;while(x)sprintf(S,"%c%s",_[x%i],s),strcpy(s,S),x/=i;x=s;}

Try it online!

Description:

char s[99],S[99];           // Two strings, s and S (capacity 99)
i;                          // A variable to store the length of the string
f(x,_)char*_;{              // f takes x and string _
    i=strlen(_);            // set i to the length of _
    *s=*S=0;                // empty s and S
    while(x)                // loop until x is zero
        sprintf(S,"%c%s",   // print into S a character, then a string
                _[x%i],s),  // character is the x%i'th character of _, the string is s
        strcpy(s,S),        // copy S into s
        x/=i;               // divide x by the length of the string (and loop)
    x=s;}                   // return the string in s

1
If you start at the end of a buffer and work backwards, you can avoid sprintf. My C version is 53 bytes, with the output buffer provided by the caller. You could do one strcpy at the end if you want to copy the bytes to the start of a buffer.
Peter Cordes

That is brilliant. I don't care if its an awkward I/O format. Awkward I/O is C claim to fame! Well done, I'd recommend putting that into the C tips post.
LambdaBeta

Posted an answer on Tips for golfing in C explaining and justifying the technique.
Peter Cordes

1

CJam, 11 bytes

liq_,@\b\f=

Try it online! Takes input as the number, then a newline, then the characters in the ASCII art.

Explanation

li           e# Read the first line and convert it to an integer
  q_,        e# Read the rest of the input and push its length n
     @\b     e# Convert the number to its base-n equivalent, as an array of numbers
        \f=  e# Map over the array, taking each element's index from the string

Since "IO is Flexible", I think you can get rid of the liq at the beginning, and that saves you 3 bytes!
Chromium

1

JavaScript, 39 bytes

Port of Rod's Python solution.

s=>g=n=>n?g(n/(l=s.length)|0)+s[n%l]:""

Try it online


Only works for n up to 64-bit, right? (Python has arbitrary-precision integers built in, but JS numbers are naturally double-precision floats that can be converted to integer). Doesn't seem to work for the larger test cases in the question, like 1928149325670647244912100789213626616560861130859431492905908574660758972167966. Oh, but the question allows answers like that. Still, should be noted.
Peter Cordes

1

SimpleTemplate, 86 bytes

Wow, this was a huge challenge!

This was made hard due to the lack of direct access to specific indexes when the index is a variable.
A bug also made it longer, requiring to store the values inside a variable.

{@setA argv.1}{@eachargv.0}{@setC C,"{@echoA.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}

Values expected:

The first argument (argv.0) can be:

  • An integer
  • A string with numbers
  • An array of integers

The second argument (argv.1) can be:

  • A string
  • An array

How this works?

It works this way:

  • Cycles through the number/string passed as the first argument
  • Sets the variable C to be an array containing:
    • The previous value C
    • The string "{@echoA."
    • The value of the loop
    • The string "}"
  • Joins everything together (using PHP's join function)
    This results in, for example, C containing "{@echoA.0}{@echoA.1}..."
  • Evaluates the result of C

Ungolfed:

{@set args argv.1}
{@each argv.0 as number}
    {@set code code, "{@echo args.", number , "}"}
    {@call join into code "", code}
{@/}
{@eval code}

You can try this code on: https://ideone.com/NEKl2q


Optimal result

If there weren't bugs, this would be the best result, accounting for the limitations (77 bytes):

{@eachargv.0}{@setC C,"{@echoargv.1.",_,"}"}{@calljoin intoC"",C}{@/}{@evalC}
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.