18
\$\begingroup\$

There's the classic run length encoding and decoding.

input   output
a3b2c5  aaabbccccc

And that's fairly straight forward and done before.

The challenge is to also account for a non-standard behavior when multiple characters precede the run length (a single digit from 0-9). Each character before the run length digit (the last digit before a non-digit or end of the string) has that value applied to it individually and printed out in order.

Some test input and output including some edge cases:

input   output
ab3c5   aaabbbccccc
a0b3    bbb  
13b1    111b
a13b1   aaa111b
a123b1  aaa111222b
aa2a1b1 aaaaab
  • A character sequence ([a-zA-Z0-9]+) must be followed by its run length length ([0-9])
  • Only valid input needs to be considered (([a-zA-Z0-9]+[0-9])*)
    • yes, empty string is valid input.
  • Input is via standard input, output via standard output

This is code golf, number of bytes determines the winner.

\$\endgroup\$
5
  • \$\begingroup\$ @AlexA. Correct. There are some esolangs that I enjoy seeing from time to time that are otherwise penalized by byte count. (I am certainly open to suggestions as to why this may be a mistake to count that way) \$\endgroup\$
    – user12166
    May 27, 2015 at 19:20
  • 4
    \$\begingroup\$ @MichaelT Scoring by characters strongly encourages compresssing the source code into UTF32, which allows the encoding of up to 4 bytes per character, but is completely unreadable. \$\endgroup\$
    – isaacg
    May 27, 2015 at 19:38
  • \$\begingroup\$ @isaacg fair 'nuff. I'll edit to change to bytes. I'll ruminate on a way to express sclipting's style to be acceptable for future challenges. \$\endgroup\$
    – user12166
    May 27, 2015 at 19:39
  • \$\begingroup\$ Is our submission supposed to complete without error if the input is the empty string? The consensus on meta is that output to STDERR can be ignored, but since you explicitly mentioned it, I have to ask. \$\endgroup\$
    – Dennis
    May 28, 2015 at 3:53
  • \$\begingroup\$ @Dennis an empty string as input should, should halt. It should not go into an infinite loop or print other text to standard output. \$\endgroup\$
    – user12166
    May 28, 2015 at 12:12

13 Answers 13

8
\$\begingroup\$

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.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ It is customary to score this as a Perl solution, where you just add 1 byte for the -p modifier. I count 45 bytes. In addition, you should be able to use \D instead of [a-z], which also eliminated the need for i. \$\endgroup\$
    – Dennis
    May 28, 2015 at 6:45
7
\$\begingroup\$

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

\$\endgroup\$
1
  • \$\begingroup\$ I do appreciate the demonstration of the problem that the bytes qualifier causes. Thank you. I'm thinking a bit on how to phrase the qualification such that languages where a single instruction is a multi-byte character don't get penalized for that style of language without allowing the UTF encoding that you showed to get in via loophole. P.S. I really like seeing the algorithmic breakdown that you provide. \$\endgroup\$
    – user12166
    May 27, 2015 at 21:12
6
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ How does it handle a123b1 ? \$\endgroup\$
    – Optimizer
    May 27, 2015 at 20:05
  • \$\begingroup\$ @Optimizer Not well. I need to tweak it a bit... \$\endgroup\$ May 27, 2015 at 20:30
  • \$\begingroup\$ @Optimizer Fixed. \$\endgroup\$ May 27, 2015 at 21:21
5
\$\begingroup\$

Javascript (ES6), 86 83 bytes

alert(prompt().replace(/(.+?)(\d)(?!\d)/g,(a,b,c)=>b.replace(/./g,y=>y.repeat(c))))

Commented:

alert( // output final result
    prompt(). // take input
    replace(/(.+?)(\d)(?!\d)/g, // replace ungreedy capture group of any characters 
                                // followed by a digit (captured)
                                // and not followed by a digit (negative lookahead)
        (a, b, c)=> // replace with a function
            b.replace(/./g, // replace all characters in b
                y=>y.repeat(c) // with that character repeated c times
            )
    )
)
\$\endgroup\$
8
  • \$\begingroup\$ Won't alert(prompt().replace(/(.+?)(\d)(?!\d)/g,(a,b,c)=>Array(c+1).join(b))) do the same? It is only 71 bytes long. \$\endgroup\$ May 28, 2015 at 0:02
  • \$\begingroup\$ @IsmaelMiguel that would only work if there was a single character before the digit. The array comprehension handles repeating each character individually. \$\endgroup\$
    – nderscore
    May 28, 2015 at 0:31
  • \$\begingroup\$ Try Array(6).join('12') and it will return '1212121212'. \$\endgroup\$ May 28, 2015 at 0:37
  • \$\begingroup\$ This one works: alert(prompt().replace(/(.+?)(\d)(?!\d)/g,(a,b,c)=>Array(-~c).join(b))) (same 71 bytes long, tested on es6fiddle.net/ia7gocwg) \$\endgroup\$ May 28, 2015 at 0:47
  • 1
    \$\begingroup\$ I found a different (obvious) way to say 3 bytes though :D \$\endgroup\$
    – nderscore
    May 28, 2015 at 2:54
4
\$\begingroup\$

CJam, 27 25 bytes

r_'A+1>.{64&1$>{])~f*o}&}

Try it online in the CJam interpreter.

How it works

r_                        e# Read a token from STDIN and push a copy.
  'A+                     e# Append the character A to the copy.
     1>                   e# Discard the first character of the copy.
       .{               } e# For each character C of the input string and the
                          e# corresponding character D of the copy:
         64&              e#   Take the bitwise and of D and 64. This pushes @
                          e#   if D is a letter and NUL if it is a digit.
            1$>           e#   Compare the result to a copy of C. This pushes 1
                          e#   if and only if D is a letter and C is a digit.
               {      }&  e#   If the result was 1, do the following:
                ]         e#     Wrap the stack in an array.
                 )~       e#     Pop and evaluate the last character.
                   f*     e#     Repeat each char in the array that many times.
                     o    e#     Print all characters.
\$\endgroup\$
3
\$\begingroup\$

Pip, 22 + 1 = 23 bytes

Uses -r flag. Note that this requires you to either 1) enter an EOF after the input (Ctrl-D on Linux, Ctrl-Z on Windows) or 2) pipe the input in from somewhere else.

(^_@<v)X_@vMa@`\D*\d+`

Explanation:

                        a is first line of stdin (from -r flag) and v is -1 (implicit)
              `\D*\d+`  Pattern (regex) object that matches zero or more non-digits
                        followed by at least one digit
            a@          Find all non-overlapping matches in a, returning a list of strings
           M            To that list, map a lambda function:
  _@<v                    Argument sans last character (equivalent to Python a[:-1])
(^    )                   Split into a list of characters
        _@v               Last character of argument
       X                  Repeat each character of the list that many times
                          (String multiplication X, like most operators, works item-wise
                          on lists)
                        Auto-print (implicit)

The result of the map operation is actually a list of lists, but by default lists are simply concatenated together when printed, so no manual conversion to string is necessary.

Example, with input a13b1:

Var a gets        "a13b1"
After regex match  ["a13" "b1"]
After map          [["aaa" "111"] ["b"]]
Final output       aaa111b

Pip has basic regex support as of... 2 days ago. Great timing!

\$\endgroup\$
4
  • \$\begingroup\$ That one works (and so does master) with the -r flag. (The question specifies that input has to come from STDIN.) \$\endgroup\$
    – Dennis
    May 28, 2015 at 4:26
  • \$\begingroup\$ @Dennis Oops, missed that. Added flag to byte count. I should've been able to use the special variable q instead of a with no extra flags, but there seems to be a bug and it's asking for the input twice. \$\endgroup\$
    – DLosc
    May 28, 2015 at 4:35
  • \$\begingroup\$ Finally a golfing language with regex support! \$\endgroup\$
    – Dennis
    May 28, 2015 at 4:37
  • \$\begingroup\$ @Dennis I see you shifting to pip now! \$\endgroup\$
    – Optimizer
    May 28, 2015 at 5:00
3
\$\begingroup\$

Pyth, 33 32 28 bytes

ssmm*vedkPdPcz-hMJf<@zT\=UzJ

Try it online: Demonstration or Test harness

Explanation

I'll explain the code using the example input aa1a23b2. Hopefully this is a bit easier to follow than without.

                               implicit: z = input string = 'aa1a23b2'
                         Uz    the indices of z: [0, 1, 2, 4, 5, 6, 7]
                  f            filter for indices T, which satisfy:
                   <@zT\=        z[T] < "="
                               this gives us the list of indices [2, 4, 5, 7], 
                               which correspond to digits in z. 
                 J             assignment, J = [2, 4, 5, 7]
               hMJ             increment all element in J: [3, 5, 6, 8]
              -            J   and remove the elements of J:
                                 [3, 5, 6, 8] - [2, 4, 5, 7] = [3, 6, 8]
            cz                 split z at these indices: ['aa1', 'a23', 'b2', '']
           P                   remove last element: ['aa1', 'a23', 'b2']
  m                            map each string d to:
   m     Pd                      map each string k of d-without-last-char to:
     ved                           int(last element of d)
    *   k                          * k
                               this creates [['a', 'a'], ['aaa', '222'], ['bb']]
 s                             sum the lists: ['a', 'a', 'aaa', '222', 'bb']
s                              sum the strings: 'aaaaa222bb'
\$\endgroup\$
2
\$\begingroup\$

Ruby 73

gets.split(/(\d)(?!\d)/).each_slice(2){|s,i|s.chars.map{|c|$><<c*i.to_i}}

Tests: http://ideone.com/L1fssb

\$\endgroup\$
2
\$\begingroup\$

JavaScript 112

alert(prompt().replace(/.*?\d+/g,function(m){for(i=n=m.length-1,o="";i--;){j=m[n];while(j--)o=m[i]+o}return o}))

\$\endgroup\$
2
\$\begingroup\$

Python 2.7, 98 bytes

import re
print"".join(c*int(m[-1])for m in 
re.findall(r".+?\d(?!\d)",raw_input())for c in m[:-1])

This just does a simple regex search for digits that aren't followed by a digit, and then does the string arithmetic on each group and joins them all back together.

\$\endgroup\$
2
  • \$\begingroup\$ You could save 2 bytes by switching from Python 2 to 3. raw_input becomes input but print needs parentheses. \$\endgroup\$
    – Alex A.
    May 28, 2015 at 1:43
  • \$\begingroup\$ True, but I prefer to golf in python 2.7. \$\endgroup\$
    – recursive
    May 28, 2015 at 1:52
1
\$\begingroup\$

Julia, 105 99 95 87 bytes

s->join([join([string(b)^(int(p[end])-48)for b=chop(p)])for p=matchall(r"\D*\d*\d",s)])

This creates an unnamed function that takes a string as input a returns a string. To call it, give it a name, e.g. f=s->....

Two array comprehensions are used here, one nested within the other. The outer comprehension acts on each match of the input string against the regular expression \D*\d*\d. The inner comprehension repeats each character of the match according to the trailing digit. The elements of the inner array are joined into a string, so the outer array is an array of strings. These are joined and returned.

In Julia, strings can be treated like character arrays. However, note that the Char and String types in Julia don't have the same methods defined; in particular, there is no method for repetition using ^ for characters. This uses a convoluted workaround:

  • Loop over the string omitting the last character, which is removed using chop().
  • Convert the current character to a string using string().
  • Convert the trailing digit, which is also a character, into an integer. However, note that, for example, int('4') does not return 4. Rather, it returns the codepoint, which in this case is 52. Thus we can subtract 48 to get back the actual integer.
  • Repeat string(b) according to int(p[end]) - 48.

Examples:

julia> f("ab3c5")
"aaabbbccccc"

julia> f("a0b3")
"bbb"

julia> f("13b1")
"111b"
\$\endgroup\$
1
\$\begingroup\$

Python 3, 148 144 136 135 Bytes

w,o,r,d=''.join,'',[],[]
for c in input()+' ':
 if'/'<c<':':d+=[c]
 elif d:o+=w(x*int(w(d))for x in r);r=[c];d=[]
 else:r+=[c]
print(o)

Thanks to Pietu1998 and mbomb007 for the suggestions.

Python 2, 161 151 147 139 138 Bytes

Maybe today's just been a long day at work, but I can't for the life of me figure out how to golf this..

w,o,r,d=''.join,'',[],[]
for c in raw_input()+' ':
 if'/'<c<':':d+=[c]
 elif d:o+=w(x*int(w(d))for x in r);r=[c];d=[]
 else:r+=[c]
print o
\$\endgroup\$
6
  • 3
    \$\begingroup\$ Changing to Python 3 saves a couple of bytes (raw_ out, parentheses to print). len(d)>0 can be replaced by d since an empty list is falsy and a non-empty list truthy. list(...) can go straight to the for. The square brackets in w([...]) are unnecessary since it's the only argument. You can remove the space in ) for. That's all the minor things I came up with so far. \$\endgroup\$ May 27, 2015 at 21:46
  • \$\begingroup\$ @Pietu1998 Thanks for the help! \$\endgroup\$
    – Kade
    May 27, 2015 at 22:13
  • \$\begingroup\$ Without changing your approach too much, you can get rid of list() since strings are iterable. You can use w=r=''. If you're willing to change it a lot, see my solution. :) \$\endgroup\$
    – recursive
    May 28, 2015 at 1:36
  • \$\begingroup\$ if c.isdigit() can become if'/'<c<':', if I'm not mistaken. \$\endgroup\$
    – DLosc
    May 28, 2015 at 5:10
  • \$\begingroup\$ @DLosc thanks, that seems to work. \$\endgroup\$
    – Kade
    May 28, 2015 at 13:04
0
\$\begingroup\$

Java 7, 175 bytes

String c(String s){String r="",a[];for(String x:s.split("(?<=(\\d)(?!\\d))")){a=x.split("");for(int i=0,j,l=a.length-1;i<l;i++)for(j=0;j++<new Short(a[l]);r+=a[i]);}return r;}

The challenge is harder than it looks, imo..

Ungolfed & test code:

Try it here.

class M{
  static String c(String s){
    String r = "",
           a[];
    for(String x : s.split("(?<=(\\d)(?!\\d))")){
      a = x.split("");
      for(int i = 0, j, l = a.length-1; i < l; i++){
        for(j = 0; j++ < new Short(a[l]); r += a[i]);
      }
    }
    return r;
  }

  public static void main(String[] a){
    System.out.println(c("ab3c5"));
    System.out.println(c("a0b3"));
    System.out.println(c("13b1"));
    System.out.println(c("a13b1"));
    System.out.println(c("a123b1"));
    System.out.println(c("aa2a1b1"));
    System.out.println(c("123"));
  }
}

Output:

aaabbbccccc
bbb
111b
aaa111b
aaa111222b
aaaaab
111222
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.