sed, 299+1
Yes, sed can find a llama. No, sed can't do math. This is the longest answer so far, at 299+1 characters, because I had to teach sed to count.
This answer requires a sed with extended regular expressions (sed -E
or sed -r
). I used OpenBSD sed(1). Input is one string per line. (Therefore, the string may not contain a newline.) Output is a line of numbers, or nothing.
Usage (+1 character for -r
):
$ echo 'All arms on all shoulders may ache.' | sed -rf llama.sed
1 2 12 26 30
Source code (299 characters):
s/%/z/g
s/(.*)[Aa]/\1%/
s/(.*)[Mm](.*%)/\1%\2/
s/(.*)[Aa]((.*%){2})/\1%\2/
s/(.*)[Ll]((.*%){3})/\1%\2/
s/(.*)[Ll]((.*%){4})/\1%\2/
/(.*%){5}/!d
s/[^%]/z/g
:w
s/(z*)%/\10 z\1/
s/z*$//
s/z0/1/
s/z1/2/
s/z2/3/
s/z3/4/
s/z4/5/
s/z5/6/
s/z6/7/
s/z7/8/
s/z8/9/
s/([0-9]z*)z9/z\10/g
s/(z*)z9/1\10/
/[%z]/bw
The program first replaces the llama with five %
. (All %
in this program are literal.) The first command s/%/z/g
changes any %
to z
in the input line. The next five commands find the llama, so All arms on all shoulders may ache. becomes A%% arms on %ll shoulders %ay %che. Because each .*
is greedy, I always finds the llama on the right: llama llama would become llama %%%%%. If I can't get five %
, then /(.*%){5}/!d
deletes the input line and skips the next commands.
s/[^%]/z/g
changes every character but %
to z
. Then I enter a loop. s/(z*)%/\10 z\1/
changes the first %
to 0
, copies zero or more z
from left to right, and adds one more z
to right. This is so the number of z
will equal the index. For example, zz%zzz%...
becomes zz0 zzzzzzzz%...
because the first %
was at index 2, and the next %
is at index 8. s/z*$//
removes extra z
from the end of the string.
The next eleven commands count z
by removing each z
and counting up from 0
. It counts like zzz0
, zz1
, z2
, 3
. Also, 1zzzz9
becomes z1zzz0
(later 23
), or zzzz9
becomes 1zzz0
(later 13
). This loop continues until there are no more %
or z
.