Skip to main content
capitalized Sed 'cause I saw Bash capitalized elsewhere
Source Link

sedSed, 162 bytes

sed, 162 bytes

Sed, 162 bytes

Source Link

sed, 162 bytes

sed 'h;G;G;G' |sed '1s/.*/&, &, bo-b\L&/i;2s/^.*/Banana-fana fo-f\L&/;3s/^.*/Fee-fi-mo-m\L&/;4s/$/!/;tx;:x;s/o-\([bfm]\)\1/o-/i;tz;s/\(o-[bfm]\)[^aeiou]\+/\1/;:z'

I did not know sed very well before I did this. I, uh, know it a lot better, now. The first sed in the pipeline duplicates the name three times so it becomes "Bob\nBob\nBob\nBob" instead of just "Bob". The next sed does the heavy lifting.

Expects input on stdin like echo Name |sed ...

Ungolfed:

sed 'h                           ;# copy to hold buffer
G                                ;# append newline + hold buffer to pattern
G                                ;# ditto for next two G's
G' |sed '1s/.*/&, &, bo-b\L&/i   ;# 1st line -> X, X bo-bx (lowercase)
2s/^.*/Banana-fana fo-f\L&/      ;# 2nd line -> Banana-fana fo-fx
3s/^.*/Fee-fi-mo-m\L&/           ;# 3rd line -> Fee-fi-mo-mx
4s/$/!/                          ;# bang the 4th line!
tx                               ;# jump to :x if any s/// has matched
:x                               ;# spoiler alert: it has! reset t-flag
s/o-\([bfm]\)\1/o-/i             ;# match some o-cc where c = [bfm]
tz                               ;# if that matched, branch to :z
s/\(o-[bfm]\)[^aeiou]\+/\1/      ;# replace o-[bfm] plus consonants with o-[bfm]
:z                               ;# target of tz, skips over previous s///'

A couple of notes. The first four matches, 1s, 2s, 3s, 4s, transform the output into something not quite correct. Bob has become bo-bbob, Fred has become fo-ffred, and Mike has become mo-mmike. Kay would become mo-mkay, mkay?

Then, we need to replace either bo-bbob with bo-ob, or bo-bkay with bo-bay. To do that, we can use a feature where we do one s/// substitution, and then branch if it succeeded, jumping over the second one that we now want to skip. But if it missed, we want to fall through the branch and do the next substitution.

The t[label] command does that, branching only if a previous s/// matched. But at the beginning of the script I already did one s/// for each line (the leading numbers in 1s, 2s, etc. are addresses; they mean the command is only performed if the address matches). So no matter what line we're on, 1, 2, 3, or 4, at least one s/// has matched. (I tried doing it the other way around, massaging the names and then adding the "Banana-etc." after, but got stuck that way, and trying to do it all at once would cause some repetition.) Fortunately, the flag can be cleared by taking a branch, so we do that with "tx ; :x". tx branches to the x label, and :x is the x label.

Whew! That clears the palate for the final two substitutions. We try one, and if it succeeds we branch over the other, otherwise we do the second one. Either way we end up at the :z label and the pattern buffer contains one line of lyrics which is printed to stdout.

Thanks for tricking me into spending enough time with the sed man page and Texinfo manual to finally understand how do to more than sed s/foo/bar/