Increment base-36 strings

20

6

This is a code golf version of a similar question I asked on stack earlier but thought it'd be an interesting puzzle.

Given a string of length 10 which represents a base 36 number, increment it by one and return the resulting string.

This means the strings will only contain digits from 0 to 9 and letters from a to z.

Base 36 works as follows:

The right most digit is incremented, first by using 0 to 9

0000000000 > 9 iterations > 0000000009

and after that a to z is used:

000000000a > 25 iterations > 000000000z

If z needs to be incremented it loops back to zero and the digit to its left is incremented:

000000010

Further rules:

  • You may use upper case or lower case letters.
  • You may not drop leading zeros. Both input and output are strings of length 10.
  • You do not need to handle zzzzzzzzzz as input.

Test Cases:

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

Jack Hales

Posted 2018-07-28T02:48:41.077

Reputation: 331

@JoKing Code-golf, cool ideas, and efficiency I guess. – Jack Hales – 2018-07-28T03:08:43.587

@JoKing I just edited the question to explain the golf puzzle a bit better, the aim is to create the function or "cycler" to turn one string into the next, the i = i + 1 part of a for loop. – Jack Hales – 2018-07-28T03:15:07.173

@JoKing changed to bytes. – Jack Hales – 2018-07-28T03:15:57.620

7I like the idea of implementing just the increment operation because it has the potential for strategies other than base-converting there and back. – xnor – 2018-07-28T03:16:56.660

@xnor I was thinking the same, I am trying to do the puzzle now and I was thinking of the ability to use it in a for-loop or while. for (i = "000"; i == "zzz"; i = up(i)) {} or something. – Jack Hales – 2018-07-28T03:18:16.343

@JoKing you can use uppercase, you can add to the base-X as much as you want, it just has to be an iterating function that works with string AND integer, capital or not. And no you cannot truncate leading 0's. Will explain the bonus better now. – Jack Hales – 2018-07-28T03:25:39.827

2

Welcome to PPCG! This is a nice challenge idea, however as some comments have pointed out, some parts of the specification are unclear. For the future I recommend using our sandbox where you can get feedback on a challenge before posting it.

– Laikoni – 2018-07-28T10:15:25.077

1suggest you add something like "0zzzzzzzzz" (modify the most signficant digit) as a test case. It tripped up my C solution because of an off-by-one-error. – O.O.Balance – 2018-07-28T13:11:45.297

Is there a codegolf style that gives points for readability? – TJR – 2018-07-30T03:02:55.170

"increment it by one and return the resulting string." <- is an in-place operation ok as well? – Felix Palmen – 2018-07-30T08:24:15.840

1added an entry assuming it's ok -- a C entry already does it as well. – Felix Palmen – 2018-07-30T09:58:12.493

@FelixPalmen yes :D – Jack Hales – 2018-07-31T22:07:18.113

Do I have to return leading zeros? – Magic Octopus Urn – 2018-10-31T14:00:18.220

@MagicOctopusUrn "You may not drop leading zeros." – Ørjan Johansen – 2018-10-31T17:03:48.277

Answers

6

05AB1E, 10 bytes

Input is in uppercase.

Code

1ì36ö>36B¦

Explanation

1ì           # Prepend a 1 to the number
  36ö        # Convert from base 36 to decimal
     >       # Increment by 1
      36B    # Convert from decimal to base 36
         ¦   # Remove the first character

Uses the 05AB1E encoding. Try it online! or Verify all test cases.

Adnan

Posted 2018-07-28T02:48:41.077

Reputation: 41 965

Can be 8 bytes in the new version of 05AB1E.

– Kevin Cruijssen – 2018-10-31T13:47:49.637

8

Japt, 13 bytes

n36 Ä s36 ù0A

Try it online! and Verify test cases

Takes input as a string

Explanation

n36            converts input to base 36
    Ä           +1
      s36       to base 36 string
          ù0A   left-pad with 0 to length 10

crashoz

Posted 2018-07-28T02:48:41.077

Reputation: 611

Welcome to Japt! :) – Shaggy – 2018-07-28T14:37:07.943

8

JavaScript (ES6), 45 bytes

Saved 4 bytes thanks to @O.O.Balance

s=>(parseInt(1+s,36)+1).toString(36).slice(1)

Try it online!

Arnauld

Posted 2018-07-28T02:48:41.077

Reputation: 111 334

You're insane, good one. +1 – Jack Hales – 2018-07-29T03:38:08.657

2

45 bytes: https://bit.ly/2K5tjw0

– O.O.Balance – 2018-07-29T09:22:17.807

I don't think ES8 anymore after latest golf... – Downgoat – 2018-07-30T18:04:28.753

@Downgoat Thanks! You're right. Updated. – Arnauld – 2018-07-30T18:10:21.283

7

Haskell, 58 bytes

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

Try it online!

A very brute-force strategy: generate all the length-10 base-36 strings in order, and find the one that comes after the input in the list. Take an enormous amount of time on strings far from the start of the list.


Haskell, 60 bytes

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

Try it online!

Reads the string left to right until it reaches a character followed by a suffix of all z's, which may be empty. Increments that character, and replaces the z's with 0's.

xnor

Posted 2018-07-28T02:48:41.077

Reputation: 115 687

6

C, 82 81 53 50 bytes

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

Directly modifies the input string; input and output is in upper case. Try it online here. Thanks to Arnauld for golfing 24 bytes and to ceilingcat for golfing 3 more bytes.

Ungolfed:

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)
 }

O.O.Balance

Posted 2018-07-28T02:48:41.077

Reputation: 1 499

I think this should be safe: 60 bytes

– Arnauld – 2018-07-28T15:02:37.433

Actually, you don't really need another pointer: 57 bytes (it does assume that the byte stored immediately before the string is NUL but ... well, it works ^^)

– Arnauld – 2018-07-28T15:05:59.777

1@Arnauld You can't assume a zero byte before the string... – Jakob – 2018-07-28T16:44:55.040

1@Jakob I'm not 100% sure about that. We define languages by their implementations. This is C (gcc) running on a TIO VM, where the memory can be -- I think -- assumed to be initially cleared. (I've seen other C answers that make similar assumptions.) – Arnauld – 2018-07-28T17:06:10.087

@Arnauld I don't think you can make that assumption – even if the memory is initially cleared, you can't make any assumptions about the memory layout of the program calling the function. But I think your golf is valid regardless, because you stop when a character is smaller than 90 – so it can never read past the start of the string. – O.O.Balance – 2018-07-28T17:22:11.297

2By including the testing environment in the 'implementation', I may be taking it a stage too far indeed. But you may still use the 60-byte version which does not rely on any memory assumption. – Arnauld – 2018-07-28T23:27:39.393

1

@Arnauld I've golfed another 4 bytes. It really should be safe, since we don't have to handle ZZZZZZZZZZ. ErikF's answer does the same, but even shorter: https://codegolf.stackexchange.com/a/169468/79343

– O.O.Balance – 2018-07-30T23:20:15.603

6

Stax, 7 bytes

ûæ≥╡►N▀

Run and debug it

Explanation:

|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

wastl

Posted 2018-07-28T02:48:41.077

Reputation: 3 089

6

C (gcc), 50 48 bytes

An explicit carry flag wasn't necessary after restructuring the loop to end as soon as no carry would happen. The 9->A adjustment is performed during the loop check.

Thanks to ceilingcat for the suggestion.

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

Try it online!


Original version: 71 57 bytes

This version uses a carry flag to propagate updates: I set it to truthy to begin the increment. The string is modified in-place and only accepts 0-9, A-Z. The tricky part was making sure that 9->A got handled correctly on carries.

Edit: I repurposed the input pointer as the carry flag.

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

Try it online!

ErikF

Posted 2018-07-28T02:48:41.077

Reputation: 2 149

5

Perl 6, 34 32 30 bytes

Thanks to nwellnhof for -2 bytes through the use of the o operator to combine functions

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

Try it online!

Function that converts the argument to base 36, adds 1, converts back and then formats it. Now uses the same tactic as Adnan's answer to preserve the leading zeroes.

Jo King

Posted 2018-07-28T02:48:41.077

Reputation: 38 234

{S/.//}o{base :36(1~$_)+1: 36} for 30 bytes. – nwellnhof – 2018-07-31T09:50:26.333

@nwellnhof Neat! I haven't ever thought to use o when golfing before, but I can see where it might be useful! – Jo King – 2018-07-31T10:08:15.447

Ah, it's a pity that .succ (increment by one) doesn't work

– Jo King – 2018-08-01T10:26:41.377

5

Online Turing Machine Simulator, 745 bytes

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,<

Online interpreter

Erik the Outgolfer

Posted 2018-07-28T02:48:41.077

Reputation: 38 134

4

MATL, 12 bytes

36ZAQ5M10&YA

Try it online!

           % 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

sundar - Reinstate Monica

Posted 2018-07-28T02:48:41.077

Reputation: 5 296

4

Haskell, 63 bytes

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

Try it online! Reverses the string and checks the first character:

  • A 9 is replaced by an a.
  • A z is replaced by a 0 and recursively the next character is checked.
  • All other characters are incremented using succ, the successor function which can be used on Chars because they are an instance of the Enum class.

Finally the resulting string is reversed again.

Laikoni

Posted 2018-07-28T02:48:41.077

Reputation: 23 676

4

6502 (NMOS*) machine code routine, 26 bytes

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

*) uses an "illegal" opcode ISB/0xF3, works on all original NMOS 6502 chips, not on later CMOS variants.

Expects a pointer to a 10-character string in $fb/$fc which is expected to be a base-36 number. Increments this number in-place.

Doesn't do anything sensible on invalid input (like e.g. a shorter string) -- handles ZZZZZZZZZZ "correctly" by accident ;)

Commented disassembly

; 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

Example C64 assembler program using the routine:

Online demo

screenshot

Code in ca65 syntax:

.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

Felix Palmen

Posted 2018-07-28T02:48:41.077

Reputation: 3 866

165C02 version can discard the ISB, then use INC after the LDA (), Y (and .done moves up by one line) and be shorter by one byte. – peter ferrie – 2018-08-03T20:11:41.827

@peterferrie does the 65C02 have an INC for the accu? – Felix Palmen – 2018-08-04T07:22:45.950

@peterferrie ok, it does, nice -- that's what I was missing in the first place on the 6502 :) – Felix Palmen – 2018-08-04T07:37:29.210

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.

Titus

Posted 2018-07-28T02:48:41.077

Reputation: 13 814

68 bytes: Try it online!

– Night2 – 2018-07-29T06:13:37.203

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

– Night2 – 2018-07-29T06:22:07.067

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 – 2018-07-29T11:58:59.743

1Nice 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 – 2018-07-29T13:32:47.607

3

Apl (Dyalog Unicode), 30 28 24 bytes

Thanks to ngn for the hint to save some bytes.

(f⍣¯1)1+f←36⊥1,(⎕D,⎕A)⍳⊢

Try it online!

  • Requires ⎕IO of 0

  • Uses upper case

jslip

Posted 2018-07-28T02:48:41.077

Reputation: 721

why not go one step further and make '1', part of f? then 1↓ will become part of its inverse – ngn – 2018-08-12T11:30:14.230

@ngn Nice, thanks! – jslip – 2018-08-12T13:31:34.930

even shorter: (⎕D,⎕A)⍳'1', -> 1,(⎕D,⎕A)⍳ – ngn – 2018-08-12T13:42:49.033

one final improvement - it can be rewritten as a train: (f⍣¯1)1+f←36⊥1,(⎕D,⎕A)⍳⊢

– ngn – 2018-08-12T13:54:01.223

3

Retina 0.8.2, 12 bytes

T`zo`dl`.z*$

Try it online! Explanation: The dl part of the substitution destination expands to 0-9a-z while the o copies that to the source, resulting in z0-9a-z (although the second z gets ignored as it can never match). This increments the matched digits. The .z*$ part of the pattern matches the last non-z digit plus all trailing zs, thus handling the carry from their increment to 0.

Neil

Posted 2018-07-28T02:48:41.077

Reputation: 95 035

3

Ruby, 40 bytes

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

Try it online!

  1. Convert the string to an integer interpreting it as base 36
  2. Add 1
  3. Convert back to base 36 string
  4. Left pad with 0s

"zzzzzzzzzz" returns an 11-long string

Asone Tuhid

Posted 2018-07-28T02:48:41.077

Reputation: 1 944

3

brainfuck, 109 bytes

,[>>,]<+[++++<[<--->>-<-]-[<->>+<---]<[[-]>-------<]+>>[[+<+>]<<+[>+<------]>>]-[<+>-----]<++++<]<[<<]>>[.>>]

Try it online!

Nitrodon

Posted 2018-07-28T02:48:41.077

Reputation: 9 181

This is what I was keen to see! – Jack Hales – 2018-07-31T22:07:41.147

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'

O.O.Balance

Posted 2018-07-28T02:48:41.077

Reputation: 1 499

Nice! For future reference in older Java you can pad with something like "".format("%10s",t).replace(' ','0') – Jakob – 2018-07-28T16:40:15.097

@Jakob Thanks, that's what I was looking for. – O.O.Balance – 2018-07-28T17:09:29.030

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 – 2018-07-28T20:31:24.980

@Okx Nice approach. 2 more bytes: "1"+s => 1+s – O.O.Balance – 2018-07-28T21:22:58.723

2

Python 2, 88 bytes

def f(s):L,R=s[:-1],s[-1:];return s and[[L+chr(ord(R)+1),f(L)+'0'][R>'y'],L+'a'][R=='9']

Try it online!

Increments the string "by hand".

Chas Brown

Posted 2018-07-28T02:48:41.077

Reputation: 8 959

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.

Neil

Posted 2018-07-28T02:48:41.077

Reputation: 95 035

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.

Florrie

Posted 2018-07-28T02:48:41.077

Reputation: 831

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.

Οurous

Posted 2018-07-28T02:48:41.077

Reputation: 7 916

1

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

– Laikoni – 2018-07-29T12:13:10.703

@Laikoni Edited in, thanks! – Οurous – 2018-07-29T20:10:48.653

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.

ngm

Posted 2018-07-28T02:48:41.077

Reputation: 3 974

You can do way better than this!! I think I have 72 bytes, if you can find the right built-in... – Giuseppe – 2018-07-30T15:03:56.770

Oops...thought this challenge was code bowling! – ngm – 2018-07-30T15:06:28.230

Well the built-in is strtoi to get you started; there are a couple more golfing tricks to get it down to 72. – Giuseppe – 2018-07-30T15:09:40.647

1strtoi is limited to rather small numbers though? I gave up on it a while ago. – ngm – 2018-07-30T15:12:37.600

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

– Giuseppe – 2018-07-30T15:19:09.990

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
| +   '

Sasha

Posted 2018-07-28T02:48:41.077

Reputation: 431

1

Wolfram Language (Mathematica), 39 bytes

IntegerString[#~FromDigits~36+1,36,10]&

Try it online!

alephalpha

Posted 2018-07-28T02:48:41.077

Reputation: 23 988

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)

trolley813

Posted 2018-07-28T02:48:41.077

Reputation: 225

I don't think you need the f=. Anonymous functions are usually considered find in code golf. – mypetlion – 2018-07-30T22:28:56.103

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)

Blue

Posted 2018-07-28T02:48:41.077

Reputation: 26 661

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.

Geoff Reedy

Posted 2018-07-28T02:48:41.077

Reputation: 2 828

@ETHproductions whoops, thanks for the catch – Geoff Reedy – 2018-08-01T00:46:47.717

1

Zsh, 41 36 bytes

echo ${(l:10::0:)$(([##36]36#$1+1))}

Try it online!

Noskcaj

Posted 2018-07-28T02:48:41.077

Reputation: 421

0

Jelly, 21 bytes

ØBḊiⱮḅ‘bɗ36Ż9¡ṫ-9‘ịØB

Try it online!

Uses uppercase. TIO link allows for lower/mixed case too.

Erik the Outgolfer

Posted 2018-07-28T02:48:41.077

Reputation: 38 134

0

Elixir, 70 bytes

fn x->"1"<>x=Integer.to_string 1+String.to_integer("1"<>x,36),36;x end

Explanation:

Prepends 1 to the input, converts it to an integer in base 36, increments it, converts it to a string in base 36, and matches it to "1" <> x (reverse concatenation), then returns x.

Try it online!

Okx

Posted 2018-07-28T02:48:41.077

Reputation: 15 025

0

Perl 5 -F, 47 bytes

($_=/z/?0:/9/?a:++$_)&&last for reverse@F;say@F

Try it online!

Xcali

Posted 2018-07-28T02:48:41.077

Reputation: 7 671

0

Powershell, 79 78 82 bytes

+4 bytes: z and 9 inside an argument string fixed

$i=1
"$args"[9..0]|%{$r=([char]($i+$_)+'0a')[2*($i*$_-eq57)+($i*=$_-eq'z')]+$r};$r

Less golfed test script:

$f = {

$i=1                    # increment = 1
"$args"[9..0]|%{        # for chars in positions 0..9 in the argument string (in reverse order)
    $c=[char]($i+$_)    # Important! A Powershell calculates from left to right
                        # Therefore the subexpression ($i+$_) gets a value before the subexpression ($i=$_-eq122)
    $j=2*($i*$_-eq57)+  # j = 2 if the current char is '9' and previous i is 1
        ($i*=$_-eq122)  # j = 1 if the current char is 'z' and previous i is 1
                        # j = 0 othewise
                        # side effect is: i = 1 if the current char is 'z' and previous i is 1, i = 0 othewise
    $c=($c+'0a')[$j]    # get element with index j from the array
    $r=$c+$r            # accumulate the result string
}
$r                      # push the result to a pipe

}

@(
    ,("09fizzbuzz" , "09fizzbv00")
    ,("0000000000" , "0000000001")
    ,("0000000009" , "000000000a")
    ,("000000000z" , "0000000010")
    ,("123456zzzz" , "1234570000")
    ,("00codegolf" , "00codegolg")
) | % {
    $s,$expected = $_
    $result = &$f $s
    "$($result-eq$expected): $result"
}

Output:

True: 09fizzBv00
True: 0000000001
True: 000000000a
True: 0000000010
True: 1234570000
True: 00codegolg

mazzy

Posted 2018-07-28T02:48:41.077

Reputation: 4 832

0

C# (.NET Core), 125 bytes

a=>{var x="";for(int i=9;;i--){var y=a[i]==90?'0':a[i]==57?'A':(char)(a[i]+1);x=y+x;a=a.Remove(i);if(y>48)break;}return a+x;}

Try it online!

Ungolfed:

a => {
    var x = "";                 // initialize x
    for (int i = 9; ; i--)      // starting at 9 (length of string minus one) and decrementing i indefinitely
    {
        var y = a[i] == 90 ?        // if the last character of a is 'Z'
            '0' :                       // y = '0'
            a[i] == 57 ?                // if the last character of a is '9'
                'A':                        // y = 'A'
                (char)(a[i] + 1);           // y = the ascii value of last character plus 1
        x = y + x;                  // prepend y to x
        a = a.Remove(i);            // remove the last character of a
        if (y > 48)                 // if y is a character other than '0',
            break;                      // break from the loop
    }
    return a + x;               // return the remainder of a, with x appended
}

Meerkat

Posted 2018-07-28T02:48:41.077

Reputation: 371