# Program to Spoonerise words [duplicate]

A spoonerisation is swapping the first letter/pronounceable syllable of two or more words.

Challenge: Write a program to spoonerise two words in the shortest characters possible.

Rules:

1. If the first letter is a consonant, you must include subsequent letters until you reach a vowel. (e.g. 'thanks' - the th gets removed and put on the front of the other word).
2. With words that start with vowels, do not remove anything from the start of the word.

Good luck :)

UPDATE: Multiple word spoonerisms are not strictly applicable, however from a programatic view we must cater for them so this is the rule: Every word must change. Example:

Weird Keen Monkey -> Meird Ween Konkey OR Keird Meen Wonkey NOT Meird Keen Wonkey

Also 'y' is treated as a vowel (just to simplify things a bit)

## marked as duplicate by Mego♦, FryAmTheEggman, isaacg code-golf StackExchange.ready(function() { if (StackExchange.options.isMobile) return; $('.dupe-hammer-message-hover:not(.hover-bound)').each(function() { var$hover = $(this).addClass('hover-bound'),$msg = $hover.siblings('.dupe-hammer-message');$hover.hover( function() { $hover.showInfoMessage('', { messageElement:$msg.clone().show(), transient: false, position: { my: 'bottom left', at: 'top center', offsetTop: -7 }, dismissable: false, relativeToBody: true }); }, function() { StackExchange.helpers.removeMessages(); } ); }); }); Jan 14 '16 at 3:22

• To clarify, does "big apple" become "ig bapple", and does "ant eater" remain the same? – Joey Adams Aug 16 '11 at 22:26
• indeed - unless you can think of a better rule in which case I will add it in there :) – Alex Coplan Aug 16 '11 at 22:27
• A "better rule" might involve using a word list to find an "optimal" spoonerization, but that would be a different and more complex problem. – Joey Adams Aug 16 '11 at 22:32
• I'm sorry but I have to downvote the question, which wasn't well prepared. So the answers were coming in, while the question wasn't cleared. Related discussion: more discipline Place to prepare challenges and to find and remove ambiguities, beside chat: Sandbox mk II – user unknown Aug 20 '11 at 16:21
• The original question says "spoonerise two words". That seemed clear, and downvoting answers (including mine) that followed that spec doesn't sit right with me. The updated question says "every word must change". How should "a" in "a pack of lies" or "I" in "I like my bike" change? Presumably, the intent is that every word that starts with a consonant should change? Sorry, but I think the original was clearer, even though the examples of spoonerisms weren't examples of input. – DCharness Aug 21 '11 at 6:35

## Ruby (60)(61)(93)(80)(75)(71) (69 / 57)

Program changed to handle the new requirement of handling multiple words.

EDIT: Golfed down to 80. 75. 71. 69.

w=[];gets.gsub(/(\S*?)([aeiouy]\S*)/i){w+=[$2,' ',$1]};$><<w.pop+w*''  If we're only spoonerizing words that start with a consonant, here's a solution in 73. 65. (I realized I can just use scan instead of gsub.) 57. $><<gets.gsub(p=/\b[^aeiouy\s]+/i){($'+$+$&).scan(p)[0]}  Old program (two words only): p='(.*?)([aeiou].+)';puts gets.gsub(/#{p} #{p}/i,'\3\2 \1\4')  • Sorry - didn't see your answer until I posted mine. – Lowjacker Aug 17 '11 at 0:01 • No problem. I figure it's the simplest approach with Ruby anyway. And I learned a couple more tricks from seeing yours ;) – migimaru Aug 17 '11 at 0:03 • echo "I like brasilian football" | irb spo-2.rb p='(.*?)([aeiou].+)';puts gets.gsub(/#{p} #{p}/i,'\3\2 \1\4') fI like brasilian ootball – user unknown Aug 20 '11 at 6:15 • The original problem only asked for spoonerizing two words. I don't know when the spec changed, but I'll fix this later. – migimaru Aug 20 '11 at 8:23 • From the question log A lack of pies was part of the initial question - 2 words (lack, pies) is the number of words starting with a consonant, isn't it? – user unknown Aug 20 '11 at 15:51 ## Haskell, 81 f[(a,b),(c,d)]=unwords[c++b,a++d] main=interact$f.map(break(elem"aeiou")).words

• May I ask you, after seeing 3 solutions failing miserably for untrivial input, how you handle I like brazilian football? (3 words, starting with consonants, and one word, just being one character? What about 'Why do you cheat'? :) – user unknown Aug 20 '11 at 6:27
• y is treated as a vowel therefore dy who chou yeat - off the top of my head, but when I wrote the question I was only aiming for 2 words – Alex Coplan Aug 20 '11 at 7:36

## Ruby, 57 56

This only works for the original problem (with only two words).

$><<gets.sub(/#{r='([^aeiou]*)(.+)'} #{r}/i,'\3\2 \1\4')  • Assuming the input is always valid, you can replace \w+ with .+ to save another character. – migimaru Aug 17 '11 at 0:55 • echo "consonants are really evil" | irb spo-1.rb$><<gets.sub(/#{r='([^aeiou]*)(.+)'} #{r}/i,'\3\2 \1\4') onsonants are really cevil – user unknown Aug 20 '11 at 6:13

## J, 77

Answers the original version of the question, "spoonerise two words"; a solution for the changed question may follow.

Couldn't shrink this to compete with the Ruby answers, so fell back on my more-familiar Perl.

exit([:;3 1 2 0 4{[:,({.@I.@e.&'aeiouAEIOU'({.;' ';~}.)]);._2@,&' ')&.stdin''

• ,&' ' appends a space

• (...);._2 splits on the last character (the space) and applies the parenthesized code to each element (i.e., each word)

• {. @ I. @ e.&'aeiouAEIOU' finds the index of the first vowel in that word

• ({.;' ';~}.) splits the word into leading consonants (if any) and a tail, with a space at the end (each in a "box", so J doesn't pad them to matching lengths)

• , flattens the 2r x 3c matrix formed by the preceding into a 6-element list

• 3 1 2 0 4{ takes all those elements but the trailing space, swapping the lead segments of the words

• ; unboxes and concatenates the elements

• (...)&.stdin'' does roughly the same as Perl's -p, reading stdin and echoing the result of "..." to stdout

• the explicit exit suppresses J's prompt for more input

## Perl, 43 (question v1), 91 79 (question v2) [107 to handle numerals in the phrase]

v1

Run with -p option (counted as 3 chars).

$p='([^aeiou]*)(.+)';s/$p $p/$3$2$1$4/i  Same technique as the Ruby answers. Using -p saves 9 characters over bracketing the code with $_=<>; and ;print for explicit IO.

v2

Run with -lp (counted as 4 chars).

push@a,$1while s/\b([^ aeiouy\d]+)(?=[aeiouy])/$n++/ei;unshift@a,pop@a;s/(\d+)/$a[$1]/g


Rotates all the consonant-starts of words one word forward.

Updated: Add vowel lookahead, so it handles "to the nth degree" more gracefully ("do te nth thegree", not "do te th nthegree").

Numerals: user unknown asked about handling "There is no winner in 2011", because of the numerals. Adding markers around the numbers my solution uses, it can handle that:

push@a,$1while s/\b([^ aeiouy\0\d]+)(?=[aeiouy])/"\0".$n++."\0"/ei;unshift@a,pop@a;s/\0(\d+)\0/$a[$1]/g


Small question, big discussion....

• echo "I like my bike" | perl5.10.1 -p spoon.pl bI like my ike – user unknown Aug 20 '11 at 6:19
• I'm of the opinion that numerals and doing special case handling for words like 'nth' are beyond the spec. We're already treating 'y' as a vowel in all cases (even in words like 'you'), so I don't see why you're starting to take pronunciation into account. – migimaru Aug 22 '11 at 15:38
• @migimaru: With 'nth', pronunciation wasn't my concern, but motion of the entire word. Hard to tell, the way this question has progressed, what a solution should handle or not. Anyhow, nicely done with the ruby solution. – DCharness Aug 22 '11 at 15:54

### CSharp - 236

List<string> f(string w) {var t="aeiou".ToCharArray();var q=w.Split(' ').Where(c=>!t.Contains(c[0]));var i=q.Count()-1;return q.Select(c=>q.Select(x=>x.Substring(0,x.IndexOfAny(t))).ToList()[i--]+c.Substring(c.IndexOfAny(t))).ToList();}

• Is this a program or a function? – user unknown Aug 20 '11 at 14:27

## Scala 244

val s=readLine
def f(a:String,b:String)=a.replaceAll("^[^aeiouy]+",b.replaceAll("[aeiouy].*",""))
val l=("((^| )[^aeiouyAEIOUY]+)([^ ]+)".r findAllIn s map(_.trim)).toList
println(s.replaceAll(l(0),f(l(0),l(1))).replaceAll(l(1),f(l(1),l(0))))


My code contains 4 y (one of them lowercase) to handle why and rythm in a useful manner.

### Scala 248, updated for new challenge (change all consonantic words)

val w=readLine.split(" ")
val c=w.filter(_.matches("[^aeiouyAEIOUY].*"))
val l=c.size
var k=0
println((for(i<-0 to w.size-1)yield{if(w(i)==c(k%l)){k+=1
c(k-1).replaceAll("^[^aeiouy]+",c(k%l).replaceAll("[aeiouy].*",""))}else w(i)}).mkString(" "))


### ungolfed, and test cases:

val samples = List ("bad salad", "I tell smooth", "Sentence with vowel in the end", "tain bruck is faboo")
def konsInit (s: String) = s.matches ("[^aeiouyAEIOUY].*")
def flipInit (a: String, b: String) = a.replaceAll ("^[^aeiouy]+", b.replaceAll ("[aeiouy].*", ""))
def spoonize (sentence: String) {
val words = sentence.split (" ")
val kwords = words.filter (konsInit);
val len = kwords.size
var k = 0
val spoonies = for (i <- 0 to words.size-1) yield {
if (words (i) == kwords (k%len)) {
k += 1
flipInit (kwords (k-1), kwords (k%len))
} else words (i)
}
println (spoonies.mkString (" "))
}
samples.foreach (spoonize)


• Is 'nth' considered a regular word? Abbrevations without vowels, numbers, dates or sentence marks have not been discussed too - do you handle 'There is no winner in 2011'? My dictionary contains no word between nozzle and nuance. But meanwhile I recognized that all others interpret the question different than me, and try to solve the big apple` problem. I guess I will delete my post. – user unknown Aug 21 '11 at 17:13