In this challenge, your task is to decipher a string. Luckily, the algorithm is pretty simple: reading from left to right, each encountered digit N (0 to 9) must be replaced with the character which is N+1 positions before it.

Example

The input string "Prog2am0in6" would be decoded this way:

example

Hence, the expected output is "Programming".

Clarifications and rules

  • The input string will contain ASCII characters in the range 32 - 126 exclusively. You can assume that it will never be empty.
  • The original deciphered string is guaranteed not to contain any digit.
  • Once a character has been decoded, it may in turn be referenced by a subsequent digit. For instance, "alp2c1" should be decoded as "alpaca".
  • References will never wrap around the string: only previous characters can be referenced.
  • You can write either a full program or a function, which either prints or outputs the result.
  • This is code golf, so the shortest answer in bytes wins.
  • Standard loopholes are forbidden.

Test cases

Input : abcd
Output: abcd

Input : a000
Output: aaaa

Input : ban111
Output: banana

Input : Hel0o W2r5d!
Output: Hello World!

Input : this 222a19e52
Output: this is a test

Input : golfin5 3s24o0d4f3r3y3u
Output: golfing is good for you

Input : Prog2am0in6 Puz0les7&1Cod74G4lf
Output: Programming Puzzles & Code Golf

Input : Replicants 4re3lik448ny3oth8r5mac6in8.8T64y'r371it9376a1b5n1fit7or2a1h2z17d.
Output: Replicants are like any other machine. They're either a benefit or a hazard.
share|improve this question
    
Can we receive the input as an array of single character strings? Can we assume that the number will never be greater than 9? – fəˈnɛtɪk 20 hours ago
    
@fəˈnɛtɪk Regarding the input format: I'd say no, unless this is the only acceptable format for your language. We're dealing with single digits rather than numbers. So yes: it's guaranteed to be <= 9 but you may encounter several digits in a row. – Arnauld 20 hours ago
    
Would 1bbab be a valid input (with expected output of abbab)? In other words, can the references wrap around the string? – Luke 20 hours ago
    
@Luke Good point. No, 1bbab is not valid. I've added a clarification about that. – Arnauld 20 hours ago

22 Answers 22

Java 7, 81 bytes

void a(char[]a){for(int i=0;i<a.length;i++)if(a[i]>47&a[i]<58)a[i]=a[i-a[i]+47];}

Try it online!

share|improve this answer

C, 52 49 bytes

f(char*s){for(;*s++;)*s>47&*s<58&&(*s=s[47-*s]);}

Edits the input string directly.

Try it online!

Alternative 50-byte version:

f(char*s){for(;*s++;)*s=abs(*s-57)>9?*s:s[47-*s];}

Recursive version, 49 bytes:

f(char*s){*s>47&*s<58&&(*s=s[47-*s]);*s++&&f(s);}
share|improve this answer

Haskell, 55 bytes

o#c|c>'/',c<':'=o!!read[c]:o|1<2=c:o
reverse.foldl(#)[]

Usage example: reverse.foldl(#)[] $ "Prog2am0in6 Puz0les7&1Cod74G4lf" -> "Programming Puzzles & Code Golf". Try it online!

Reduce the string to a reverse copy of itself with the numbers replaced by the corresponding chars. "reverse", because this way we have easy access to the string so far when indexing the numbers. Reverse it again.

share|improve this answer
1  
Wow, I have written this exact solution but I was slow in posting it :) Well, at least now I know it was a good one, +1 – Leo 19 hours ago

05AB1E, 11 bytes

vydiÂyèëy}J

Try it online!

Explanation

v            # for each character y in input
 ydi         # if y is a digit
    Â        #    push a reversed copy of the string we've built up so far
     yè      #    push the character at index y in the reversed string
       ë     # else
        y    #    push y
         }   # end if
          J  # join stack to a single string
             # output top of the stack at the end of the loop
share|improve this answer

JavaScript (ES6), 59 53 bytes

f=x=>/\d/.test(x)?f(x.replace(/\d/,(m,o)=>x[o+~m])):x

Saved 7 bytes thanks to fəˈnɛtɪk.

f=x=>/\d/.test(x)?f(x.replace(/\d/,(m,o)=>x[o+~m])):x

console.log(f("Prog2am0in6"));
console.log(f("abcd"));
console.log(f("a000"));
console.log(f("ban111"));
console.log(f("Hel0o W2r5d!"));
console.log(f("this 222a19e52"));
console.log(f("golfin5 3s24o0d4f3r3y3u"));
console.log(f("Prog2am0in6 Puz0les7&1Cod74G4lf"));
console.log(f("Replicants 4re3lik448ny3oth8r5mac6in8.8T64y'r371it9376a1b5n1fit7or2a1h2z17d."));

share|improve this answer
    
.charAt(...) can be replaced with [...] for savings of 7 bytes – fəˈnɛtɪk 20 hours ago
    
x.charAt(...) is equivalent to x[...] – fəˈnɛtɪk 19 hours ago
    
@fəˈnɛtɪk Yep, I thought I tried that before but it threw an error. Thanks! – Tom 19 hours ago
1  
o-m-1 can be replaced with o+~m. – Neil 18 hours ago
1  
Because f is called recursively, the character count of the program must include the f= part, so this is 54 bytes, not 52. – user5090812 16 hours ago

Retina, 37 bytes

Byte count assumes ISO 8859-1 encoding.

\d
$*«»
r1+`(?<=(.)(?<-2>.)*)(«)*»
$1

Try it online!

Explanation

\d
$*«»

Replace each digit d with d «s, followed by one ». We need the latter a) to be able to recognised positions where d = 0 and b) as a separator between adjacent digits.

r1+`(?<=(.)(?<-2>.)*)(«)*»
$1

Repeatedly (+) match the regex on the first line from right to left (r) and then replace the left-most match (1) with the substitution on the second line.

The regex itself matches one of our now unary digits and counts the number of «s in group 2. The lookbehind then matches d characters with (?<-2>.)* before capturing the referred-to character in group 1. The string of «s and » is then replaced with the captured character.

share|improve this answer

MATL, 21 19 17 16 bytes

"@t4Y2m?UQ$y]]&h

Try it at MATL Online!

Explanation

        % Implicitly grab input as a string
"       % For each character in the input
  @     % Push that character to the stack
  t     % Make a copy of it
  4Y2   % Push the pre-defined array '0123456789' to the stack
  m     % Check if the current character is part of this array (a digit)
  ?     % If it is
    UQ  % Convert it to a number and add 1 (N)
    $y  % Make a copy of the element N-deep in the stack. MATL uses one-based indexing
        % So 1$y is the element at the top of the stack, 2$y is the next one down, etc.
  ]     % End of if statement
        % Non-digit characters remain on the stack as-is
]       % End of for loop
&h      % Horizontally concatenate the entire stack to form a string
        % Implicitly display the result
share|improve this answer
    
Nice use of $y in the new version! – Luis Mendo 19 hours ago
    
@LuisMendo Thanks! Yea stack-based languages are a good fit for this challenge – Suever 19 hours ago
    
@LuisMendo Unfortunately this could have been shortened even more if U only worked for digits. Unfortunately 'e'U yields exp(1) otherwise I could have gotten rid of the 4Y2 stuff – Suever 19 hours ago
    
Another of those Octave things... – Luis Mendo 19 hours ago

JavaScript ES6, 61 59 bytes

Thanks @Luke for golfing off 8 bytes

x=>[...x].map((p,i,a)=>a[i]=/\d/.test(p)?a[i-1-p]:p).join``

Try it online!

share|improve this answer
    
x.split`` could also be [...x], [0-9] could be \d, together saving 6B – Luke 20 hours ago
    
Currently has an error somewhere so going to fix that first – fəˈnɛtɪk 20 hours ago
    
x=>[...x].map((p,i,a)=>+p+1?a[i-1-p]:p).join`` for 46 bytes – Luke 20 hours ago
    
Fails for spaces +" " gives 0 which causes it to grab the previous character – fəˈnɛtɪk 20 hours ago

JavaScript (ES6), 51 bytes

f=
s=>s.replace(/\d/g,(c,i)=>a[i]=a[i+=~c]||s[i],a=[])
<input oninput=o.textContent=f(this.value)><pre id=o>

a is used to store the replaced digits to deal with digits referring to other digits.

share|improve this answer

Perl 5, 34 bytes

33 bytes of code + -p flag.

s/\d/substr$_,-$&-1+pos,1/e&&redo

Try it online!

s/\d/.../e replace the first digit by ... evaluated as Perl code. (with ... being substr$_,-$&-1+pos,1 in that case. substr$_,-$&-1+pos,1 returns the substring of $_ of length 1 at index -$&-1+pos, where $& is the number just matched, and pos is the index of the start of the match. We just need to redo if the replace was successful in order to replace every digit. (and the result is implicitly printed thanks to -p flag).


Old approach, 47 bytes:

44 bytes of code + -F flag.

map{$F[$i]=$F[$i-$_-1]if/\d/;++$i}@F;print@F

Try it online!

Quite straight forward actually. -F flag splits the inputs on each character into @F. map{...}@F iterates through @F (ie. every character of the input). If the character if a digit (/\d/), then we replace it by the character at index $i-$_-1. The $i is the current index variable (that we maintain by incrementing at each character seen).

share|improve this answer

Python 2, 75 71 btes

s='';j=-1
for i in input():s+=s[j-int(i)]if'/'<i<':'else i;j+=1
print s

Try it Online!

Edit: Fixed for ascii values between 32-47 ; Fixed for double decoding (eg. "alp2c1" to "alpaca")

share|improve this answer
1  
@Arnauld Nope. Sorry, i didn't read the spec closely enough. WIll modify shortly – math junkie 20 hours ago
    
It seems there is a bug. for 'Prog2am0in6 Puz0les7&1Cod74G4lf' your program prints Programming Puzzles &7Code1Golf! I tried with both TIO links shared! – Keerthana Prabhakaran 19 hours ago
    
@KeerthanaPrabhakaran Thanks! Fixed at the cost of 0 bytes! (My alternate solution didn't make the cut though) – math junkie 19 hours ago
    
Thats a great approach! – Keerthana Prabhakaran 19 hours ago
    
Can you explain '/'<i<':'. I know it's testing if it's a number but how does it work? – Matias K 16 hours ago

Jelly, 9 7 bytes

~ịṭṭµ@/

Try it online!

How it works

~ịṭṭµ@/  Main link. Argument: s

    µ    Combine the four links to the left into a chain (arity unknown).
     @   Swap the chains arguments. This makes it dyadic.
      /  Reduce s by the chain with swapped arguments. It will be called with
         right argument r (the result of the previous call, initially the first 
         character) and left argument c (the next character of s).
~            Bitwise NOT of c. This maps a digit 'd' to ~d = -(d+1), but all 
             non-digit characters 'D' to 0.
  ṭ          Tack; append c to r.
 ị           Index; select the character of the result to the right at the
             index from the result to the left. Indexing is 1-based and modular,
             so 0 is the last character, -1 the second to last, etc.
   ṭ         Tack; append the resulting character to r.    
share|improve this answer

Python 2, 59 bytes

s=''
for c in input():s+=c['/'<c<':':]or s[~int(c)]
print s

Try it online!

share|improve this answer

05AB1E, 27 17 bytes

vyDdiU)DRXèU`X}}J

Try it online!

vy             }  # For each character
  Dd              #   Push is_number
    i         }   #   If it is
     U            #     Save save it
      )DR         #     Wrap the (reversed) stack into an array
         Xè       #     Get the character at the saved index
           U`X    #     Flatten the whole stack
                J # Join 
share|improve this answer

Python 2,83 80 bytes

r=input()
for i in r:
 if'/'<i<':':r=r.replace(i,r[r.find(i)+~int(i)],1)
print r

Try it online!

  • saved 3 bytes but checking ascii instead of is digit! Thanks to math_junkie!
share|improve this answer

CJam, 13 bytes

q{_A,s#)$\;}/

Online demo.

This solution uses CJam's built-in "copy n-th item on the stack" operator $ to implement the decoding. It starts by reading the input (with q) and then looping over the characters from the input string and dumping them onto the stack (with {}/). However, inside the loop body it also duplicates each character after it has been put on the stack (with _) and checks if it's a digit by looking up its position with # in the string "0123456789", conveniently represented as A,s.

The result of this lookup is either the digit's numeric value or, if the character is not a digit, -1. The ) operator then increments that value by one, and $ replaces it with the character current at that many positions below the top of the stack. Finally, \; just removes the copy of the current input character that we made with _ from the stack, as it's no longer needed.

share|improve this answer

Japt, 24 bytes

£Xn >J?U=UhYUgJ+Y-X):PÃU

Try it online!

Explanation:

£Xn >J?U=UhYUgJ+Y-X):PÃU
£                     Ã    Iterate through the input (implicit U) 
                             X becomes the iterative item, Y becomes the index
 Xn                          Try parseInt(X)
    >J                       > -1
                               In this case, this checks if X is a digit
      ?                      If true:
       U=                      Set U to 
         UhY                     U with the char at index Y set to:     
            UgJ+Y-X               The index at -1+Y-X
                   ):        Else:
                     P         variable P (just a no-op in this case)
                       U   Finally, return U
share|improve this answer

Python 2, 58 bytes

lambda s:reduce(lambda t,c:t+(c+t)['/'<c<':'and~int(c)],s)

This is essentially a port of my Jelly answer, plus the digit check from @xnor's Python answer.

Try it online!

share|improve this answer

PHP, 79 Bytes

for(;++$i<strlen($a=&$argn);)is_numeric($l=$a[$i])?$a[$i]=$a[$i-$l-1]:0;echo$a;
share|improve this answer

Powershell, 98 82 76 bytes

param($n)($n=[char[]]$n)|%{if(48..57-match$_){$n[$j]=$n[$j-$_+47]}$j++};"$n"

Try it Online!

I'm sure there is a better way to do the casting and defining variables... I'm not sure how to redefine my $i variable inside the foreach loop which is why I define it then call it instead of the normal technique of defining and calling simultaneously.

Suggestions welcome!

EDIT It looks like powershell will redefine $i when I set it on the right side of the equation in the if statement. I did not realize it looked at that first - saved 1 byte

EDIT 2 Found another way to find the current index by using $j as an index that iterates for each foreach pass - saved 15 bytes and copied method from @AdmBorkBork for creating character arrays found here! - saved another 6 bytes

share|improve this answer

Befunge-98, 45 43 bytes

::::#@~\1p:1g::'9`!\'/`*j;'/--1g\1p\1g#;,1+

Try it online!

The idea:

  1. For each char in the input string,
    1. Write it to line 2
    2. If it is not a number, just output it
    3. Otherwise, look up the correct value, rewrite it, then output it
::::            ; There's a counter on the stack, duplicate it 4 times  ;
    #@~         ; Get the next char of input, exiting if there is none  ;
       \1p      ; At the location (counter, 1), write the input char    ;
          :1g   ; Re-obtain the char. Stack is now [counter * 4, input] ;

::                ; Stack: [counter * 4, input * 3]      ;
  '9`!\'/`*       ; If !(input > '9') and (input > '/')  ;
                  ; IE If ('0' <= input && input <= '9') ;
           j;...; ; Then execute the ...                 ;

; Stack: [counter * 4, input] ;
; The ... branch:             ;

'/-             ; input -> int. (input -= '/')             ;
   -            ; counter - int(input) - 1                 ;
                ; Stack: [counter * 3, lookupPosition ]    ;
    1g          ; Get the char that we want to find        ;
      \1p\1g#   ; Overwrite the current char (not the old) ;

; Both branches: ;
,1+             ; Print the number and increment the counter ;

I wasn't able to get this version shorter, but this one is 44 bytes:

s #@~\3p:3g::'9`!\'/`*j;'/--3g#;:10g3p,1+:::

Thought I'd share it because of the neat trick with s - but storing the counter on the stack leads to that 1 char improvement

share|improve this answer

Ruby, 56 46 bytes

->s{i=0;s[i]=s[i+~s[i].to_i]while i=s=~/\d/;s}

Try it online!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.