Run-length encoding

You are encouraged to solve this task according to the task description, using any language you may know.


Task

Given a string containing uppercase characters (A-Z), compress repeated 'runs' of the same character by storing the length of that run, and provide a function to reverse the compression.

The output can be anything, as long as you can recreate the input with it.



Example

 Input: WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW
 Output: 12W1B12W3B24W1B14W


Note: the encoding step in the above example is the same as a step of the Look-and-say sequence.




/*REXX program  encodes and displays a string  by using a  run─length  encoding scheme. */
parse arg input .                                /*normally, input would be in a file.  */
default= 'WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW'
if input=='' | input==","  then input=   default /*Not specified?  Then use the default.*/
encode= RLE(input) ;     say '  input='  input   /*encode input string;  display input. */
                         say 'encoded='  encode  /*                      display run─len*/
decode= RLD(encode);     say 'decoded='  decode  /*decode the run─len;   display decode.*/
if decode==input  then say 'OK'; else say "¬ OK" /*display yay or nay (success/failure).*/
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
err: say;    say "***error***  input data isn't alphabetic:"   c;       say;     exit 13
/*──────────────────────────────────────────────────────────────────────────────────────*/
RLE: procedure;  parse arg x;     $=             /*$:  is the output string  (so far).  */
                        Lx= length(x)            /*get length of the plain text string. */
       do j=1  by 0  to Lx;  c= substr(x, j, 1)  /*obtain a character from plain text.  */
       if \datatype(c, 'M')  then call err       /*Character not a letter?  Issue error.*/
       r= 0                                      /*R:  is NOT the number of characters. */
                     do k=j+1  to Lx  while substr(x, k, 1)==c   /*while characters ≡ C */
                     r= r + 1                    /*bump the replication count for a char*/
                     end   /*k*/
       j= j + r + 1                              /*increment (add to) the DO loop index.*/
       if r==0  then $= $ ||      c              /*don't use  R  if it is equal to zero.*/
                else $= $ || r || c              /*add character to the encoded string. */
       end   /*j*/;                   return $   /*return the encoded string to caller. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
RLD: procedure;  parse arg x;     $=             /*$:  is the output string  (so far).  */
                        Lx= length(x)            /*get the length of the encoded string.*/
       do j=1  by 0  to Lx;  c= substr(x, j, 1)  /*obtain a character from run encoding.*/
       if \datatype(c, 'W')  then do;   $= $ || c;     j= j + 1;     iterate /*j*/
                                  end            /* [↑]  a loner char, add it to output.*/
       #= 1                                      /*          [↓]  W:  use a Whole number*/
              do k=j+1  to Lx  while datatype(substr(x,k,1), 'w') /*while numeric*/
              #= # + 1                           /*bump the count of the numeric chars. */
              end   /*k*/
       n= substr(x, j, #) + 1                    /*#:  the length of encoded character. */
       $= $  ||  copies( substr(x, k, 1), n)     /*N:  is now the number of characters. */
       j= j + # + 1                              /*increment the DO loop index by D+1.  */
       end   /*j*/;                   return $   /*return the decoded string to caller. */