# Shorten text with Run Length Encoding

Shorten (or not) text using run length encoding

Input:

heeeello
woooorld


Output:

1h4e2l1o
1w4o1r1l1d
• Print to stdout.
• Stderr is of course discarded.
• Assume there are hidden testcases (no embedding of the output)
• Input/Output as ASCII
• Any language is accepted
• You can (typically) save quite a bit if you ignore all ones, e.g. w4orld instead of 1w4o1r1l1d (you'd need to escape numerics, e.g. f111 -> f3\1´). But then it would be a near-duplicate of this: codegolf.stackexchange.com/questions/6774 – primo Sep 14 '12 at 9:54
• As it is it's close enough to Run-Length Encoding that I vote to close as dupe. It's not going to provide any new challenge or points of interest. – Peter Taylor Sep 14 '12 at 12:15
• Bonus points for whoever manages to find a fixpoint. – FUZxxl Sep 15 '12 at 18:11
• Run-Length Encoding may be the same at its core but the input format and the required output format are very different. – mroman Sep 15 '12 at 18:16
• @FUZxxl, 22 is a trivial fixpoint. – Peter Taylor Sep 17 '12 at 18:15

# Perl: 46 → 36 or 27 characters

perl -pe's|((.)\2*)|@x=split//,$1;@x.$x[0]|eg'

All hail @ardnew for coming up with the idea of using the tr///c operator to count the number of characters in the matched string instead of splitting:

perl -pe's|((.)\2*)|$1=~y///c.$2|eg'


Degolfed:

while(defined($_ = <>)) {$_ =~ s{((.)\2*)}           # match 1 or more consecutive identical non-newlines
{
($1 =~ y///c ) # count the number of characters in$1
.                  # and concatenate it
$2 # with the first matched character }eg; # execute substitution, match "global" print$_;                   # print the modified line
}


Usage:

$perl -pe's|((.)\2*)|$1=~y///c.$2|eg' infile  or via STDIN $ perl -pe's|((.)\2*)|$1=~y///c.$2|eg'
heeeello


prints

1h4e2l1o

• You're short-changing yourself on your character count - I count 37 characters including 1 for the p option. – Gareth Sep 14 '12 at 22:30
• You can save 10 chars by using s|((.)\2*)|$1=~y///c.$2|eg, which sums to 27 total chars (using the same character counting rules as @Gareth) – ardnew Sep 15 '12 at 3:29

## J, 35 31 characters

,(](":@#,{.);.1~1,2~:/\])1!:1[1


Usage:

   ,(](":@#,{.);.1~1,2~:/\])1!:1[1
heeeello
1h4e2l1o
,(](":@#,{.);.1~1,2~:/\])1!:1[1
woooorld
1w4o1r1l1d


# Bash: 104 characters

while read s;do e=;while [[ $s ]];do c=${s:0:1};n=${s##+($c)};e+=$[${#s}-${#n}]$c;s=$n;done;echo$e;done


Sample run:

bash-4.2$while read s;do e=;while [[$s ]];do c=${s:0:1};n=${s##+($c)};e+=$[${#s}-${#n}]$c;s=$n;done;echo $e;done <<END heeeello woooorld END 1h4e2l1o 1w4o1r1l1d  ## Zsh, 117 while read s;do n=1;for i in {1..$#s};do if [[ $s[i] !=$s[i+1] ]];then echo -n $n$s[i];n=0;fi;((n++));done;echo;done


Run it like this:

zsh script.zsh < infile


### De-golfed

while read s; do                      # while stdin has more
n=1                                 # repeat counter
for i in {1..$#s}; do # for each character if [[$s[i] != $s[i+1] ]]; then # same as next one? echo -n$n\$s[i]                 # print if no
n=0
fi
((n++))
done
echo                                # newline between words
done

• Are those white spaces necessary or can you shorten if [' to 'if[' etc? – mroman Sep 14 '12 at 11:19
• The [[ construct is a command on it's own (like [) and has to be separated from other commands. As to using [ over [[, it requires the arguments to be quoted so four " need to be added. – Thor Sep 14 '12 at 12:00

## APL (24)

,↑{(⍕⍴⍵),⊃⍵}¨B⊂⍨B≠¯1⌽B←⍞


# Burlesque (17B)

{=[{J[-jL[Q}\m}WL

{=[{^^[~\/L[Sh}\m}WL


Older/Alternative and longer versions:

{=[{^^L[Sh\/-]Sh.+}m[\[}WL
{=[{^^L[Sh\/-][-.+}m[\[}WL
{=[{^^L[Sh\/-~.+}m[\[}WL
{=[{^^L[Sh\/-].+}\m}WL
{=[{^^L[Sh\/[~.+}\m}WL
{=[{^^L[Sh\/[~_+}\m}WL
{=[{^^L[Sh\/fc.+}\m}WL
{=[{^^L[Sh\/-~.+}\m}WL
{=[{^^L[Sh\/-]\/}\m}WL


# rs, 19 chars

This doesn't really count because I created rs way after this was posted...but it was fun anyway!

(.)(\1*)/(^^\1\2)\1


Try it here!