以36为基数递增字符串


20

这是我之前在堆栈上问过的类似问题的代码高尔夫版本,但认为这将是一个有趣的难题。

给定一个长度为10的字符串,该字符串表示一个基数为36的数字,将其加1并返回结果字符串。

这意味着字符串将只包含数字09和来信az

Base 36的工作原理如下:

最右边的数字递增,首先使用09

0000000000> 9次迭代> 0000000009

然后使用ato z

000000000a> 25次迭代> 000000000z

如果z需要增加,它将循环回到零,并且左边的数字将增加:

000000010

进一步的规则:

  • 您可以使用大写或小写字母。
  • 不得丢掉前导零。输入和输出均为长度为10的字符串。
  • 您不需要处理zzzzzzzzzz作为输入。

测试用例:

"0000000000" -> "0000000001"
"0000000009" -> "000000000a"
"000000000z" -> "0000000010"
"123456zzzz" -> "1234570000"
"00codegolf" -> "00codegolg"

@JoKing Code-Golf,不错的主意,效率,我猜。
杰克·海尔斯,

7
我喜欢仅执行增量操作的想法,因为它除了执行基本转换外,还具有其他策略的潜力。
xnor18年

2
欢迎来到PPCG!这是一个很好的挑战性想法,但是,正如一些注释所指出的那样,规范的某些部分尚不清楚。今后,我建议您使用我们的沙盒,在发布之前,您可以在其中获得有关挑战的反馈。
Laikoni

1
建议您添加类似的内容"0zzzzzzzzz"(修改最重要的数字)作为测试用例。由于出现一个错误,它使我的C解决方案崩溃了。
OOBalance

1
假设没问题,添加了一个条目-C条目也已经做到了。
菲利克斯·帕尔曼

Answers:





7

Haskell,58个字节

d=['0'..'9']
f s=snd(span(<s)$mapM(\_->d++['a'..'z'])d)!!1

在线尝试!

一种非常强力的策略:按顺序生成所有长度为10的base-36字符串,并在列表中的输入之后找到一个。在远离列表开头的字符串上花费大量时间。


Haskell,60个字节

q '9'='a'
q c=succ c
f(h:t)|any(<'z')t=h:f t|r<-'0'<$t=q h:r

在线尝试!

从左到右读取字符串,直到到达一个字符,后跟所有z的后缀(可能为空)。递增该字符,并将z替换为0。


6

Stax,7 个字节

ûæ≥╡►N▀

运行并调试

说明:

|3^|3A|z Full program, implicit input
|3       Convert from base 36
  ^      Increment
   |3    Convert to base 36
     A|z Fill with "0" to length 10
         Implicit output

6

C(gcc)50 48字节

重组循环以结束没有进位的情况后,无需显式进位标志。在循环检查期间执行9-> A调整。

感谢天花板猫的建议。

f(char*s){for(s+=9;(*s+=*s-57?1:8)>90;*s--=48);}

在线尝试!


原始版本:71 57字节

此版本使用进位标志传播更新:我将其设置为true以开始增量。该字符串就地进行了修改,仅接受0-9,AZ。棘手的部分是要确保9-> A在进位时得到正确处理。

编辑:我将输入指针重新用作进位标志。

f(s){for(char*t=s+9;s;)*t--+=(s=++*t>90)?-43:7*!(*t-58);}

在线尝试!


6

C,82 81 53 50字节

f(char*s){for(s+=10;*--s>89;)*s=48;*s+=*s-57?1:8;}

直接修改输入字符串;输入和输出均为大写。在这里在线尝试。感谢Arnauld高尔夫球24字节,感谢ceilingcat高尔夫球3个字节。

取消高尔夫:

f(char *s) { // function taking a string argument
     for(s += 10; *--s > 89; ) // skip to the least significant digit, and step through the string until you hit something other than a 'Z' (90 is the ASCII code for 'Z') ...
         *s = 48; // ... replacing each digit with a zero (48 is the ASCII code for '0')
         *s += // the next digit has to be incremented:
         *s - 57 // if it's not a '9' (ASCII code 57) ...
         ? 1 // ... that is straightforward ...
         : 8; // ... otherwise it has to be replaced with an 'A' (ASCII code 65 = 57 + 8)
 }

我认为这应该是安全的:60个字节
Arnauld

1
@Arnauld您不能在字符串之前假定零字节...
Jakob

1
@Jakob我不太确定这一点。我们通过它们的实现来定义语言。这是在TIO VM上运行的C(gcc),我认为可以在其中清除内存。(我已经看到其他C答案做出类似的假设。)
Arnauld

2
通过将测试环境包含在“实现”中,我可能确实把它作为一个阶段。但是您仍然可以使用不依赖任何内存假设的60字节版本。
Arnauld

1
@Arnauld我又打了4个字节。确实应该很安全,因为我们不必处理ZZZZZZZZZZ。ErikF的答案是一样的,但甚至更短:codegolf.stackexchange.com/a/169468/79343
OOBalance

5

在线图灵机模拟器,745字节

init:0
accept:2
0,0
0,0,>
0,1
0,1,>
0,2
0,2,>
0,3
0,3,>
0,4
0,4,>
0,5
0,5,>
0,6
0,6,>
0,7
0,7,>
0,8
0,8,>
0,9
0,9,>
0,a
0,a,>
0,b
0,b,>
0,c
0,c,>
0,d
0,d,>
0,e
0,e,>
0,f
0,f,>
0,g
0,g,>
0,h
0,h,>
0,i
0,i,>
0,j
0,j,>
0,k
0,k,>
0,l
0,l,>
0,m
0,m,>
0,n
0,n,>
0,o
0,o,>
0,p
0,p,>
0,q
0,q,>
0,r
0,r,>
0,s
0,s,>
0,t
0,t,>
0,u
0,u,>
0,v
0,v,>
0,w
0,w,>
0,x
0,x,>
0,y
0,y,>
0,z
0,z,>
0,_
1,_,<
1,0
2,1,-
1,1
2,2,-
1,2
2,3,-
1,3
2,4,-
1,4
2,5,-
1,5
2,6,-
1,6
2,7,-
1,7
2,8,-
1,8
2,9,-
1,9
2,a,-
1,a
2,b,-
1,b
2,c,-
1,c
2,d,-
1,d
2,e,-
1,e
2,f,-
1,f
2,g,-
1,g
2,h,-
1,h
2,i,-
1,i
2,j,-
1,j
2,k,-
1,k
2,l,-
1,l
2,m,-
1,m
2,n,-
1,n
2,o,-
1,o
2,p,-
1,p
2,q,-
1,q
2,r,-
1,r
2,s,-
1,s
2,t,-
1,t
2,u,-
1,u
2,v,-
1,v
2,w,-
1,w
2,x,-
1,x
2,y,-
1,y
2,z,-
1,z
1,0,<

在线口译


5

Perl 6的34个32 30字节

多亏了nwellnhof通过使用o运算符来合并函数,因此获得了-2个字节

{S/.//}o{base :36(1~$_)+1: 36}

在线尝试!

该函数将参数转换为基数36,再加1,转换回去然后格式化它。现在使用与Adnan的答案相同的策略来保留前导零。


{S/.//}o{base :36(1~$_)+1: 36}30个字节。
nwellnhof

@nwellnhof整洁!我以前从未想过要o在打高尔夫球时使用它,但是我可以看到它可能有用的地方!
Jo King

啊,可惜.succ(递增一个)不起作用
Jo King

4

MATL,12字节

36ZAQ5M10&YA

在线尝试!

           % Implicit input
36ZA       % convert from base 36 to decimal
Q          % increment by 1
5M         % bring the 36 back on stack (done this way to avoid needing space separator after this)
10         % = minimum length of output string
&YA        % convert back to base 36 with those arguments
           % Implicit output

4

Haskell,63个字节

r.f.r
f('9':r)='a':r
f('z':r)='0':f r
f(c:r)=succ c:r
r=reverse

在线尝试!反转字符串并检查第一个字符:

  • 9都被替换a
  • 一种 z替换为a,0然后递归检查下一个字符。
  • 所有其他字符都使用递增succ,该后继函数可以在Chars上使用,因为它们是Enum类的实例

最后,生成的字符串再次反转。


4

6502(NMOS *)机器代码例程,26个字节

A0 09 F3 FB B1 FB C9 5B 90 07 A9 30 91 FB 88 10 F1 C9 3A D0 04 A9 41 91 FB 60

*)使用“非法”操作码ISB/0xF3,可在所有原始NMOS 6502芯片上使用,不适用于更高版本的CMOS型号。

需要一个指向10个字符的字符串的指针 $fb /中$fc需要应该是一个以36为基数的数字。就地增加此数字。

对无效输入不做任何明智的操作(例如较短的字符串)-处理 ZZZZZZZZZZ意外地“正确” ;)

评论拆解

; function to increment base 36 number as 10 character string
;
; input:
;   $fb/$fc: address of string to increment
; clobbers:
;   A, Y
 .inc36:
A0 09       LDY #$09            ; start at last character
 .loop:
F3 FB       ISB ($FB),Y         ; increment character ("illegal" opcode)
B1 FB       LDA ($FB),Y         ; load incremented character
C9 5B       CMP #$5B            ; > 'z' ?
90 07       BCC .checkgap       ; no, check for gap between numbers and letters
A9 30       LDA #$30            ; load '0'
91 FB       STA ($FB),Y         ; and store in string
88          DEY                 ; previous position
10 F1       BPL .loop           ; and loop
 .checkgap:
C9 3A       CMP #$3A            ; == '9' + 1 ?
D0 04       BNE .done           ; done if not
A9 41       LDA #$41            ; load 'a'
91 FB       STA ($FB),Y         ; and store in string
 .done:
60          RTS

使用例程的示例C64汇编程序:

在线演示

screenshot

ca65语法中的代码:

.import inc36   ; link with routine above

.segment "BHDR" ; BASIC header
                .word   $0801           ; load address
                .word   $080b           ; pointer next BASIC line
                .word   2018            ; line number
                .byte   $9e             ; BASIC token "SYS"
                .byte   "2061",$0,$0,$0 ; 2061 ($080d) and terminating 0 bytes

.bss
b36str:         .res    11

.data
prompt:         .byte   "> ", $0

.code
                lda     #<prompt        ; display prompt
                ldy     #>prompt
                jsr     $ab1e

                lda     #<b36str        ; read string into buffer
                ldy     #>b36str
                ldx     #$b
                jsr     readline

                lda     #<b36str        ; address of array to $fb/fc
                sta     $fb
                lda     #>b36str
                sta     $fc
                jsr     inc36           ; call incrementing function

                lda     #<b36str        ; output result
                ldy     #>b36str
                jmp     $ab1e

; read a line of input from keyboard, terminate it with 0
; expects pointer to input buffer in A/Y, buffer length in X
.proc readline
                dex
                stx     $fb
                sta     $fc
                sty     $fd
                ldy     #$0
                sty     $cc             ; enable cursor blinking
                sty     $fe             ; temporary for loop variable
getkey:         jsr     $f142           ; get character from keyboard
                beq     getkey
                sta     $2              ; save to temporary
                and     #$7f
                cmp     #$20            ; check for control character
                bcs     checkout        ; no -> check buffer size
                cmp     #$d             ; was it enter/return?
                beq     prepout         ; -> normal flow
                cmp     #$14            ; was it backspace/delete?
                bne     getkey          ; if not, get next char
                lda     $fe             ; check current index
                beq     getkey          ; zero -> backspace not possible
                bne     prepout         ; skip checking buffer size for bs
checkout:       lda     $fe             ; buffer index
                cmp     $fb             ; check against buffer size
                beq     getkey          ; if it would overflow, loop again
prepout:        sei                     ; no interrupts
                ldy     $d3             ; get current screen column
                lda     ($d1),y         ; and clear 
                and     #$7f            ;   cursor in
                sta     ($d1),y         ;   current row
output:         lda     $2              ; load character
                jsr     $e716           ;   and output
                ldx     $cf             ; check cursor phase
                beq     store           ; invisible -> to store
                ldy     $d3             ; get current screen column
                lda     ($d1),y         ; and show
                ora     #$80            ;   cursor in
                sta     ($d1),y         ;   current row
                lda     $2              ; load character
store:          cli                     ; enable interrupts
                cmp     #$14            ; was it backspace/delete?
                beq     backspace       ; to backspace handling code
                cmp     #$d             ; was it enter/return?
                beq     done            ; then we're done.
                ldy     $fe             ; load buffer index
                sta     ($fc),y         ; store character in buffer
                iny                     ; advance buffer index
                sty     $fe
                bne     getkey          ; not zero -> ok
done:           lda     #$0             ; terminate string in buffer with zero
                ldy     $fe             ; get buffer index
                sta     ($fc),y         ; store terminator in buffer
                sei                     ; no interrupts
                ldy     $d3             ; get current screen column
                lda     ($d1),y         ; and clear 
                and     #$7f            ;   cursor in
                sta     ($d1),y         ;   current row
                inc     $cc             ; disable cursor blinking
                cli                     ; enable interrupts
                rts                     ; return
backspace:      dec     $fe             ; decrement buffer index
                bcs     getkey          ; and get next key
.endproc

1
65C02版本可以丢弃ISB,然后在LDA(),Y(和.done向上移动一行)并缩短一个字节之后使用INC。
彼得·费里

@peterferrie 65C02的INC是否有INC?
Felix Palmen '18

@peterferrie好的,它确实很好-那就是我在6502的第一位置上所缺少的东西:)
Felix Palmen

3

视网膜0.8.2,12字节

T`zo`dl`.z*$

在线尝试!说明:dl替换目标的一部分扩展到,0-9a-z而将其o复制到源,从而导致z0-9a-z(尽管第二个z将被忽略,因为它永远不会匹配)。这将增加匹配的数字。.z*$模式的部分与最后一个非z数字加所有尾随zs 匹配,从而处理从其增量到的进位0


3

Ruby,40个字节

->s{(s.to_i(36)+1).to_s(36).rjust 10,?0}

在线尝试!

  1. 将字符串转换为整数,将其解释为基数36
  2. 加1
  3. 转换回基数为36的字符串
  4. 左垫带0s

"zzzzzzzzzz" 返回一个11位长的字符串




3

PHP, 69 64 bytes

lame version:

printf("%010s",base_convert(1+base_convert($argn,36,10),10,36));

Run as pipe with -R. Input case insensitive, output lowercase.

first approach, 69 bytes:

<?=str_pad(base_convert(1+base_convert($argn,36,10),10,36),10,'0',0);

Run as pipe with -F

looping version, also 69 bytes:

for($n=$argn;~$c=$n[$i-=1];)$f||$f=$n[$i]=$c!=9?$c>Y?0:++$c:A;echo$n;
  • PHP 7.1 only: older PHP does not understand negative string indexes,
    younger PHP will yield warnings for undefined constants.
  • requires uppercase input. Replace Y and A with lowercase letters for lowercase input.

Run as pipe with -nR

... or try them online.


68 bytes: Try it online!
Night2

Another 68 bytes version: Try it online! You can use your -R and call this one 66 bytes as well.
Night2

1
@Night2 Good approach; but it can be done even shorter: printf('%010s',($b=base_convert)(1+$b($argn,36,10),10,36)); - 59 bytes
Titus

1
Nice one. Didn't know that we could call a function like this: ($b=base_convert)(a,b,c). I'm learning from you a lot.
Night2


2

Charcoal, 14 bytes

×0⁹←⮌⍘⊕⍘S³⁶¦³⁶

Try it online! Link is to verbose version of code. Explanation:

×0⁹

Print 9 0s. This serves to pad the result.

←⮌⍘⊕⍘S³⁶¦³⁶

Convert the input from base 36, incremented it, then convert back to base 36. Then, reverse the result and print it leftwards.


2

Java 8, 90 76 56 bytes

s->Long.toString(Long.valueOf(1+s,36)+1,36).substring(1)

Accepts both upper-case and lower-case letters for input. Output is always in lower case.

Thanks to Okx for golfing 18 bytes.

Try it online here.

Ungolfed:

s -> // lambda taking a String argument and returning a String
    Long.toString(Long.valueOf(1+s,36)+1,36) // prefix input with '1' to ensure leading zeros, convert to Long using base 36, increment, then convert back to String in base 36
    .substring(1) // remove the leading '1'

Nice! For future reference in older Java you can pad with something like "".format("%10s",t).replace(' ','0')
Jakob

@Jakob Thanks, that's what I was looking for.
O.O.Balance

It's shorter to use the approach of adding a 1 at the start then removing it: s->Long.toString(Long.valueOf("1"+s,36)+1,36).substring(1)
Okx

@Okx Nice approach. 2 more bytes: "1"+s => 1+s
O.O.Balance

2

JavaScript (ES6), 89 bytes

This one is not nearly as byte-efficient as the other JavaScript entry, but I made this without noticing this rule:

Given a string of length 10

So this isn't a serious entry - just for fun! It works with strings of general length, such as 0abc, and prepends a 1 when the first digit is z, e.g. zzz -> 1000. Input must be lowercase.

s=>(l=s[s.length-1],r=s.slice(0,-1),l=='z'?f(r||'0')+0:r+(parseInt(l,36)+1).toString(36))

Explanation

The expression (A, B, C) actually means "do A, then do B, then return C", which I make use of to declare some variables I reuse in the code. s stands for "string", l means "last", r means "rest".

/*1*/ s=>(
/*2*/   l=s[s.length-1],
/*3*/   r=s.slice(0,-1),
/*4*/   l=='z'
/*5*/     ? f(r||'0')+0
/*6*/     : r+(parseInt(l,36)+1).toString(36))

This is a recursive function. For a typical string like aza, it will just increment the last character (see line 6) - azb. But for a string that ends with z, like h0gz, it will run itself on everything up to the last character (the z) and substitute a 0 in place of it (see line 5) - f(h0gz) = f(h0g) + 0 = h0h0.

The ||'0' in line 5 is so that the function works when it's called on a 1-length string (i.e. the string 'z'). Without it, f('') is called (since 'z'.slice(0, -1) is ''), which has undefined behavior (literally - try it yourself), and that's no good. The expected result of f('z') is '10', which is what we get from f('0') + 0, so we use ||'0'. (||'0' is particularly useful because it doesn't get in the way of the usual case - r being at least 1-length (s at least 2-length) - because strings are falsey only when they are 0-length.)

The method for incrementing a string is the same as used in the other JS entry: convert the base-36 "number" into an actual number, add 1, then convert it back to base-36. We don't need to worry about the 1 from incrementing 'z' ('z' -> '10'), since we never actually increment 'z' (see line 4 and 6: the last character is only incremented if it is not 'z').

Also, we never risk discarding leading zeroes, because we don't ever actually manipulate more than a single character at a time - only ever the last character in the string. The rest of the characters are cleanly sliced off as you slice any string and prepended afterwords.


2

Clean, 89 84 bytes

import StdEnv
@['9':t]=['a':t]
@['z':t]=['0': @t]
@[c:t]=[inc c:t]
r=reverse

r o@o r

Try it online!

A shorter solution thanks to Laikoni.

Clean, 115 bytes

I love it when I get to use limit(iterate...

import StdEnv
@'9'='a'
@c=inc c
?[h,'{':t]=[@h,'0': ?t]
?[h:t]=[h: ?t]
?e=e
$l=limit(iterate?(init l++[@(last l)]))

Try it online!

Produces the answer without converting bases using list matching.

  • ? :: [Char] -> [Char] performs forward carrying.
  • @ :: Char -> Char increments by one, accounting for the gap between '9' and 'z'.
  • $ :: [Char] -> [Char] increments the last character and applies ? until the value stabilizes.

1
Less fancy, but quite a bit shorter: Try it online!
Laikoni

@Laikoni Edited in, thanks!
Οurous

2

R, 152 123 bytes

function(x)f(utf8ToInt(x),10)
f=function(x,n,y=x[n]){x[n]=y+(y==57)*39+(y==122)*(-75)+1
"if"(y==122,f(x,n-1),intToUtf8(x))}

Try it online!

A completely different approach. Get the ASCII code points and recursively "increment" the right-most code point (making 0 (57) jump to to a (97) and z (122) go back to 0 (48)) until you run out of zs. Convert back to string.

Old version

function(s,w=gsub("(z)(?=\\1*$)","0",s,,T),x=regexpr(".0*$",w)[1],y=substr(w,x,x),z=chartr("0-9a-z","1-9a-z0",y))sub(p(y,"(0*$)"),p(z,"\\1"),w)
p=paste0

Try it online!

This is all text manipulation, which is does not go hand-in-hand with R code golfing.

Replace all z at end of strings with 0. Find location of last element before the newly minted trailing 0s. Find the next base 36 digit. Make the change. Be glad to have barely beaten the Online Turing Machine Simulator solution.


You can do way better than this!! I think I have 72 bytes, if you can find the right built-in...
Giuseppe

Oops...thought this challenge was code bowling!
ngm

Well the built-in is strtoi to get you started; there are a couple more golfing tricks to get it down to 72.
Giuseppe

1
strtoi is limited to rather small numbers though? I gave up on it a while ago.
ngm

Oh I see. Didn't realize the int restriction was so problematic. Bummer! For posterity, this was my failed solution: Try it online!
Giuseppe

2

Starry, 325 bytes

     + , , , , , , , , , ,     +      +   +   +`* +          + +* + +**      + * +* * '    +           + +* +* +* +*      +* `     +  + +                + +  *       +* *  '    +      +*           + +* +* +*  `   +   +           + +* +  *  **   +  + +'    +    +   ` +           + +* +  *    * .           + +* +  *   * +   '

Try it online!

Explanation:

Put-a-zero-at-the-base-of-the-stack
|     +
Read-10-digits
| , , , , , , , , , ,
Initialise-next-stack
|     +
Initialise-carry-bit
|      +
|   +   +
Do
|`
    Top-of-stack:-[output-stack]-[carry-bit]-[next-value]
    Add-Carry-bit-to-digit
    |*

    Compare-with-58-("9"=57)
    | +
    5-double-triple-sub1-double
    |          + +* + +**      + * +*
    Take-difference
    | *
    If-one-above-"9"
    | '
        set-to-"a"=97=6-double-double-double-double-add1
        |    +
        |           + +* +* +* +*      +*
    | `

    Initialise-next-carry-bit
    |     +
    |  +

    Compare-with-123-("z"=122)
    | +
    11-squared-add2
    |                + +  *       +*
    Take-difference
    | *
    If-one-above-"z"
    |  '
        Delete-current-value
        |    +
        set-carry-bit
        |      +*
        Set-to-"0"=48
        |           + +* +* +*
    |  `

    Push-value-to-stack
    |   +   +
    |           + +* +  *
    |  **

    |   +  +
While-next-value-is-not-null
| +'

Pop-carry-bit-and-null-string-terminator
|    +    +
Do
|   `
    Get-top-value
    | +
    |           + +* +  *
    |    *

    Print-it
    | .

    Pop-the-value-off-the-stack
    |           + +* +  *
    |   *
While-stack-is-not-null
| +   '


1

Python 3.6+ and gmpy2, 62 bytes

from gmpy2 import*;f=lambda s:f'{digits(mpz(s,36)+1,36):0>10}'

Try it online!

(Note that gmpy2 isn't part of Python standard library and requires separated installation)


I don't think you need the f=. Anonymous functions are usually considered find in code golf.
mypetlion

1

Pyke, 11 bytes

? b!!R+bhbt

Try it here!

? b         - Change default base of `base` command to 36 
            -  This is kind of clever because it modifies the list of characters 
            -  the command uses to exactly the same as it was originally, whilst
            -  forcing an overwrite from the default settings of 10. 
            -  The default setup works for base 36, you just have to specify it
            -  time when using the command.
            -  Literally `b.contents = modify(b.contents, func=lambda: noop)`
   !!       - The previous command returns `0123456789abcdefghijklmnopqrstuvwxyz`
            -  So we convert it into a 1 with (not not ^) for the following command:
     R+     -     "1"+input
       b    -    base(^, 36)
        h   -   ^ + 1
         b  -  base(^, 36)
          t - ^[1:]

Could be 2 bytes shorter with the following language change: If hex mode is used, change all base_36 and base_10 usages to base_92 (which isn't really base 92 in that context anyway)


1

sed, 94 bytes

s/$/#:0123456789abcdefghijklmnopqrstuvwxyz#0/
:l
s/\(.\)#\(.*:.*\1\)\(#*.\)/\3\2\3/
tl
s/:.*//

Try it online!

Sed suffers a lot for having to change the characters by lookup.


@ETHproductions whoops, thanks for the catch
Geoff Reedy


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.