Expand an encoded string

Perl/Bash 54 40+1 = 41 bytes

perl -pe's:(\D*\d*)(\d):"\$1=~s/./\$&x$2/egr":ege'

It's basically a regex within a regex. And a bit of magic.

Explanation

The outer regex /(\D*\d*)(\d)/g extracts each run-length encoded group. We capture the stuff to repeat in $1 and the number of repetitions in $2. Now we substitute each such group with the expansion of that group. For that, we evaluate the code "\$1=~s/./\$&x$2/egr" two times (as by the /ee flag on the outer substitution).

The first evaluation will only interpolate the number of repetitions into the string – the other variables are protected by a backslash. So assuming the input a14, we would now have the code $1=~s/./$&x4/egr, which will be evaluated again.

This will apply the substitution to the contents of $1 (the stuff to repeat a1). The substitution matches each character .. The $& variable holds the whole match, which we repeat x4 times. We do this /globally for each match and /return the substituted string rather than modifying the $1 variable (which is read-only). So the result of the inner substitution is aaaa1111.

The -p flag applies the substitution to each input line and prints out the result.


CJam, 33 31 27 bytes

Ughh, lack of regular expressions makes this pretty long...

qN+{:XA,s&L\:L>{])~e*[}&X}%

How it works

We loop through all characters of the input string and in each iteration, keep track of the last encountered character (starting with an empty character for the first time). Then we check if the current character is non-numeric and the last character is numeric. If so, we repeat each previous character (which has not been repeated already), the number times.

(A bit outdated code expansion)

q{                       }%        e# Read the input (q) and loop through each character
  L                                e# Put variable L (initially empty character) on stack
   A,                              e# Put variable A (equals 10) and create an array 0..9
     s                             e# Convert the array to string "0123456789"
      &                            e# Do a set intersect b/w previous char and 0-9 string
                                   e# If numeric, it gives 1 char string, otherwise 0
       \:LA,s&                     e# Swap to bring current character on top. Store it in L
                                   e# and do the same set intersect with it
              >                    e# Means we are checking that current char is non-numeric
                                   e# and previous numeric
               {      }&           e# Run this block if above is true
                ])~                e# Wrap everything not already repeated in an array and
                                   e# take out the last character and convert it to integer.
                                   e# This is the run length of the preceding string
                   e*              e# Repeat each character in the string, run length times
                     [             e# Start a new array to help when next run length is found
                        L          e# Restore the current character back on stack to be used
                                   e# in next iteration
                           )~e*    e# The last string-run-length pair is not decoded..
                                   e# So we do that now

Try it online here


rs, 43 71 chars

Well, this turned long quickly. Stupid numbers...

(\d)(\D)/\1 \2
+(\w)(\w+?)(\d)(?= |$)/\1\3 \2\3
(\w)(\d)/(\1)^^(\2)
 /

Try it here!

Original version (did not work with input like 123):

+(\D)(\D+)(\d)/\1\3\2\3
(\D)(\d)/(\1)^^(\2)

Explanation

The first line places spaces between runs containing numbers, e.g. turning a313 into a3 13.

The second line continuously expands the compressed encodings like aa5 to a5a5.

The third line converts every instance of a5 into aaaaa using the repetition operator.

The last line removes the spaces.