Given two words, spoonerise them by switching their initial consonant clusters. Fewest bytes wins.

plaster man -> master plan
blushing crow -> crushing blow
litigating more -> mitigating lore
strong wrangler -> wrong strangler
def ghi -> ghef di
few years -> yew fears

The consonants appearing before the first vowel (aeiou) are switched.

Input: Two lowercase strings that start with different consonants and each contain a vowel aeiou.

Output: The two spoonerised strings, in the right order.

For input and/or output, the two strings may also be in a list or the like, or as a single string with separator.

    var QUESTION_ID=69385,OVERRIDE_USER=20260;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/69385/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
    body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>


This is a near-dupe of this old question, but I'm hoping to write a spec that is clearer and more stable so that the old one can be closed as a dupe.

  • 5
    \$\begingroup\$ The words start with consonants. \$\endgroup\$
    – xnor
    Commented Jan 14, 2016 at 6:01
  • 22
    \$\begingroup\$ Answer should be "oozing snotter" imo~ \$\endgroup\$ Commented Jan 14, 2016 at 19:45
  • 3
    \$\begingroup\$ @PatrickRoberts I agree, but this makes the challenge a bit simpler. \$\endgroup\$
    – xnor
    Commented Jan 14, 2016 at 21:24
  • 1
    \$\begingroup\$ Not very on topic, but a nice example snow flake -> flow snake \$\endgroup\$
    – flawr
    Commented Jan 17, 2016 at 13:02
  • 2
    \$\begingroup\$ fast lucks and coy bunts are not allowed to participate \$\endgroup\$ Commented Jan 18, 2016 at 11:44

44 Answers 44


Husk, 24 19 17 bytes


Try it online!

-5 bytes from Dominic Van Essen.

-2 bytes using Γ.


mΣTΓo:↔  Tmoġ€¨aeıu
          mo             map each string to the following:
            ġ            group by
             €¨aeıu      vowel groups
         T               transpose
   Γo:                   prepend
      ↔                  the first row reversed
                         to the rest of the array
  T                      transpose back
mΣ                       concatenate into words
  • \$\begingroup\$ Should be easy to save 5 bytes here: "Input: Two lowercase strings"... \$\endgroup\$ Commented Nov 15, 2020 at 20:18
  • \$\begingroup\$ We really do be missing the question guidelines \$\endgroup\$
    – Razetime
    Commented Nov 16, 2020 at 2:04

GNU Awk 4.0, 48 characters


Sample run:

bash-4.3$ for s in 'plaster man' 'blushing crow' 'litigating more' 'strong wrangler' 'def ghi'; do
>     echo -n "$s -> "
>     awk 'split($0,a,/\<[^aeiou]+/,s)&&$0=s[2]a[2]s[1]a[3]' <<< "$s"
> done
plaster man -> master plan
blushing crow -> crushing blow
litigating more -> mitigating lore
strong wrangler -> wrong strangler
def ghi -> ghef di

Lua, 80 bytes

function f(a)return a:gsub('([^aeiou]*)(.*)%s([^aeiou]*)(.*)','%3%2 %1%4'),''end

You can test it here.


function f( a )
    return a:gsub(
        '([^aeiou]*)(.*)%s([^aeiou]*)(.*)', -- Get non-vowels, anything else, space, repeat
        '%3%2 %1%4' -- Re-arrange captures
    ),'' -- Get rid of number of gsubs (1)

You need to print the output, of course, which would add some more bytes.

  • \$\begingroup\$ Is some of the whitespace at parentheses removable? \$\endgroup\$ Commented Jan 21, 2016 at 1:23
  • \$\begingroup\$ Good catch, it is. I always forget to do those things. \$\endgroup\$
    – DavisDude
    Commented Jan 21, 2016 at 1:38

05AB1E (legacy), 20 bytes


I/O as a pair of strings.

Try it online or verify all test cases.


ε            # Map both strings in the (implicit) input-list to:
 .œ          #  Get all partitions of the current string
   2ù        #  Only keep the partitions of size 2
             #   i.e. "plaster" → [["p","laster"],["pl","aster"],["pla","ster"],
             #    ["plas","ter"],["plaste","r"]]
     ʒ       #  Filter these partitions by:
      н      #   Pop and push the first substring
       D     #   Duplicate it
        žMм  #   Remove all vowels
           Q #   And check whether it's still equal to the duplicated substring
     }θ      #  After the filter: pop and push the last 2-part partition
             #   i.e. [["p","laster"],["pl","aster"]] → ["pl","aster"]
}ø           # After the map: zip/transpose the list of 2-part partitions
             #  i.e. [["pl","aster"],["m","an"]] → [["pl","m"],["aster","an"]]
  `          # Then push both pairs separated to the stack
   R         # Reverse the second pair
             #  → ["an","aster"]
    +        # Append the substrings at the same indices
             # (which is why we use the legacy version built in Python,
             # where `+` can be used to append strings vectorized)
             #  → ["plan","master"]
     R       # And then reverse the resulting pair
             #  → ["master","plan"]
             # (after which it is output implicitly as result)

Zsh, 79 bytes

Non-regex solution, using param expansion

<<<${2:0:$n}${1:$m}\ ${1:0:$m}${2:$n}

Try it Online!

original, 121 bytes


Julia, 51 55 bytes

I was happy to find a 78-byte solution, then I saw this answer by Dennis. So, here it is in Julia.

Edit: fixed multiple match

w->replace(w,Regex('^'*"([^aeiou]+|.+ )"^3)=>s"\3\2\1")

Try it online!

(My 78-byte, non-regex solution:)

f(w,v=findfirst.(in("aeuio"),w))=[w[3-i][1:v[3-i]-1]*w[i][v[i]:end] for i=1:2]

Try it online!

  • 1
    \$\begingroup\$ Not sure what's going wrong, but "strong wrangler" => "wrong stralgner" seems to be wrangling or strangling the consonants... \$\endgroup\$ Commented Nov 24, 2020 at 13:07

sed, 44 bytes

s/([^aeiou]+)(.+) ([^aeiou]+)(.+)/\3\2 \1\4/

Try it online!


Lexurgy, 75 bytes

((!{a,e,i,o,u})+)$1 ([]*)$2 . ((!{a,e,i,o,u})+)$3 ([]*)$4=>$3 $2 . $1 $4

Input and output is period-separated (plaster.man) due to how Lexurgy handles whitespace.


Python 162

while a<0:
 if p[c]in v:
while b<0:
 if q[d]in v:
print " ".join((q[:b]+p[a:],p[:a]+q[b:]))

Matlab 169

q=strsplit(input('','s'),' ');n=Inf(1,2);for e=1:2;for w='aeiou';n(e)=min([n(e),find(q{e}==w)]);end;end;[q{2}(1:n(2)-1),q{1}(n(1):end),' ',q{1}(1:n(1)-1),q{2}(n(2):end)]

Seeks for vowels in loops and finds the first in each word. Then swaps letters


litigating more
ans =
mitigating lore

def ghi
ans =
ghef di
  • \$\begingroup\$ The spec doesn't require a single string as input, so you can probably drop the strsplit part. \$\endgroup\$
    – Sanchises
    Commented Jan 20, 2016 at 19:54

PHP 405 325


function c($i){$c=[];$l=0;while(!in_array(substr($i,$l,1),['a','e','i','o','u'])&&$l<strlen($i)){$c[]=substr($i,$l,1);++$l;}return $c;}list(,$a,$b)=$argv;$z=c($a);$x=c($b);$a=implode('',$x).substr($a,count($z),strlen($a)-count($z));$b=implode('',$z).substr($b,count($x),strlen($b)-count($x));echo $a.' -> '.$b.PHP_EOL;

Original code:

function find_first_consonants($str) {
    $consonants = [];
    $loop = 0;
    while(!in_array(substr($str, $loop, 1), [ 'a', 'e', 'i', 'o', 'u' ]) && $loop < strlen($str)) {
        $consonants[] = substr($str, $loop, 1);
    return $consonants;
list( , $strA, $strB ) = $argv;
$consonantsA = find_first_consonants($strA);
$consonantsB = find_first_consonants($strB);
$newStrA        = implode('', $consonantsB) . substr($strA, count($consonantsA), strlen($strA) - count($consonantsA));
$newStrB        = implode('', $consonantsA) . substr($strB, count($consonantsB), strlen($strB) - count($consonantsB));
echo $newStrA . ' -> ' . $newStrB . PHP_EOL;

Haskell, 55 bytes

f w|[(a,b),(c,d)]<-break(`elem`"aieou")<$>w=[c++b,a++d]

An adaptation of this answer. Input and output is a list of two strings.

Each input is broken into two pieces at the appearance of the first vowel. Then, having assigned names to the four pieces in a guard, they are recombined and outputed.

  • \$\begingroup\$ In GHC 7.10, replacing map() with the infix <$> saves two bytes. \$\endgroup\$ Commented Feb 4, 2016 at 16:37
  • \$\begingroup\$ @AndersKaseorg Thanks, changed it. \$\endgroup\$
    – xnor
    Commented Feb 5, 2016 at 20:30

Io, 141 bytes

Surprised that this is actually so long.

method(r,r :=r map(x,x splitAt("aeiou"asList map(j,x asList indexOf(j))min))flatten reverse;list(r slice(1,3)join,list(r at(3),r at(0))join))

Try it online!


Japt v2.0a0, 17 13 bytes

I/O as an array of strings


Try it

mòÏè\vÃÕvÔÕmq     :Implicit input of array
m                 :Map
 ò                :  Partition before characters that return truthy
  Ï               :  When passed through the following function
   è              :    Count
    \v            :    RegEx /[aeiou]/gi
      Ã           :End partition and map
       Õ          :Transpose
        v         :Modify first element
         Ô        :  Reverse
          Õ       :Transpose
           m      :Map
            q     :  Join

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.