59
\$\begingroup\$

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>

**Leaderboard:**


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.

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

44 Answers 44

51
\$\begingroup\$

Vim, 18 keystrokes

/[aeiou]<CR>dbwvnhp0P

The crucial trick is that pasting over something in Visual mode actually puts the old contents of the visual selection in the paste buffer.

\$\endgroup\$
3
  • \$\begingroup\$ ... oh, duh, didn't think of that. Kept getting thrown off by v being inclusive and trying to select from the vowel back. \$\endgroup\$
    – Doorknob
    Jan 14, 2016 at 2:20
  • 12
    \$\begingroup\$ As a casual vim user, I kept being amazed as I typed each successive command \$\endgroup\$
    – Aaron
    Jan 14, 2016 at 14:35
  • 5
    \$\begingroup\$ <CR> means carriage return (old typewriter term!), also known as Enter \$\endgroup\$
    – Kai Carver
    Jan 14, 2016 at 18:50
21
\$\begingroup\$

brainfuck, 238 207 bytes

,[[<+<+>>-]++++[<-------->-]-[<<-->>-----]<<+++++[----[----[------[------>>]]]]>[>>]>,]<<++++++++[<[++++<<]<++++<[++++<<]>>[>>]>>[>>]<-]<[<<]-[<+>---]>[>.>]<[<<]<<[<<]>[>>]>[.>>]<.<[<<]>[>.>]>[>>]>[>>]>[.>>]

Requires , to return 0 on EOF, 8-bit wrapping cells and the ability to move left from cell 0. In my experience, these are the most common default settings.

I'm pretty happy with this one. My first try was 314 bytes and this is certainly an improvement. :)

It works by storing every byte from input in two cells; one with the actual value of the byte and the other with the output of the following code when given (the value of the byte - 97):

[
    ----
    [
        ----
        [
            ------
            [
                ------>>
            ]
        ]
    ]
]

If the character is a consonant, it comes out of that with a non-zero value. If it's a vowel, it becomes 0. From there it's just a matter of finding where the second word starts and printing everything in order.

The 238 byte version of this program found the space character after collecting all the input. It was a headache because doing so involved creating a cell that contained 0 right where I was trying to loop over it. The way I solved that had the effect of subtracting 30 from every character in the first word and 32 from every character after it. A fairly large portion of the code was dedicated to handling that nonsense.

Now, 32 is subtracted from every character in the input loop, which is shorter and has a similar side effect that's easier to deal with. As a bonus, doing it this way allowed me to create my own space character in a shorter way: Instead of subtracting 139 from 171 (171 is what you get when you run a space through the vowel detector above), the loop that adds 32 to every character goes out of its way to also add 32 to the 171 cell. This costs four bytes there, but means I can subtract 171 from it later (instead of subtracting 139) for a net total of 3 bytes saved.

With comments:

For every input character
,[

  Make a copy
  [<+<+>>-]

  Subtract 32 from one
  ++++[<-------->-]

  Subtract 97 from the other
  -[<<-->>-----]<<+++++

  If nonzero:
  [

    Subtract 4
    ----

    If nonzero:
    [

      Subtract 4
      ----

      If nonzero:
      [

        Subtract 6
        ------

        If nonzero:
        [

          Subtract 6
          ------>>

        ]

      ]

    ]

  ]

>[>>]>,]

Add 32 to every character and the 171 that the space left behind
<<++++++++[<[++++<<]<++++<[++++<<]>>[>>]>>[>>]<-]

Go to the space
<[<<]

Subtract 171 from (32 plus 171)
-[<+>---]

~~~~~~~~~~~~~~~

Ready to print!

~~~~~~~~~~~~~~~

Print letters from the second word until the value to the left is zero
>[>.>]

Go to the beginning of the first word
<[<<]<<[<<]

Look at cells to the left of letters in the first word until reaching a zero
>[>>]

Print the rest of the letters in the first word
>[.>>]

Print a space
<.

Go to the beginning of the first word
<[<<]

Print letters from the first word until the value to the left is zero
>[>.>]

Go to the beginning of the second word
>[>>]

Look at cells to the left of letters in the second word until reaching a zero
>[>>]

Print the rest of the letters in the second word
>[.>>]
\$\endgroup\$
2
  • \$\begingroup\$ This counts y as a vowel, but the question says it's not. (nye cat -> ce nyat) \$\endgroup\$
    – xenia
    Jan 22, 2016 at 13:11
  • 1
    \$\begingroup\$ @Loovjo that's really odd, because the code that checks for vowels definitely treats y as a consonant... I'll look into why it's doing that. \$\endgroup\$ Jan 22, 2016 at 13:18
18
\$\begingroup\$

vim, 23

/[aeiou]<cr>"xd0wndb0Pw"xP

I wonder if vim is actually competitive in this challenge. Probably not with the golfing languages, but perhaps with Ruby/Python/Perl/etc.

/[aeiou]<cr>  Find the first vowel
"xd0          "Delete" (cut), to register "x, everything from here to BOL
w             Go to next word
n             Find next vowel
db            "Delete back" - delete from here to the beginning of the word
0             Go to BOL
P             Paste what we just "deleted" (cut) behind the cursor
w             Next word
"xP           Paste backwards from register "x
\$\endgroup\$
5
  • 13
    \$\begingroup\$ I do this in Insert mode, right? \$\endgroup\$
    – Alex A.
    Jan 15, 2016 at 6:57
  • 6
    \$\begingroup\$ @AlexA. ಠ_ಠ​​​​ \$\endgroup\$
    – Doorknob
    Jan 15, 2016 at 12:12
  • \$\begingroup\$ @AlexA. Insert mode would be an extra keystroke :)~ \$\endgroup\$
    – pydsigner
    Jan 15, 2016 at 20:10
  • \$\begingroup\$ @AlexA. Insert mode? Did you mean insert command? \$\endgroup\$ Jan 16, 2016 at 3:43
  • 1
    \$\begingroup\$ @BlacklightShining Nope. It was a joke because if you're in insert mode and you type that stuff, it won't execute any commands; you will have just typed it in a file. \$\endgroup\$
    – Alex A.
    Jan 16, 2016 at 4:22
17
+100
\$\begingroup\$

Python, 68 63 60 bytes

import re
lambda s:re.sub('([^aeiou]+|.+ )'*3,r'\3\2\1',s,1)

Try it online on Ideone.

How it works

The pattern string is repeated thrice (*3), resulting in the pattern

([^aeiou]+|.+ )([^aeiou]+|.+ )([^aeiou]+|.+ )

All instances will either match a non-empty string of non-vowels, or a non-empty string followed by a single space character.

The first instance will match the consonants at the beginning of the first word. Since + is greedy, it will attempt to match as many as possible, i.e., all up to the first vowel.

Because of this, the second instance will start at a vowel, so it will match the remainder of the first word, up to and including the space that separates the words.

Similarly to the first instance, the third will match all consonants at the beginning of the second word, resulting in a successful match for the entire pattern.

The raw string \3\2\1 (r prevents Python from replacing \3 etc. with control characters) reverses the order of the matches of the parenthesized patterns, i.e., it replaces them with the consonants at the beginning of the second word, then all characters from the first vowel of the first word up to the space, and finally the consonants at the beginning of the first word.

The final argument to sub (1) makes it return immediately after the first successful replacement, to avoid nonsensical replacements in the remainder of the second word. This is required since the pattern can match any string of three or more consecutive consonants.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Congrats on the bounty, for bringing the regex magic to Python with a very efficient regex. Nice explanation too. \$\endgroup\$
    – xnor
    Jan 23, 2016 at 8:22
12
\$\begingroup\$

JavaScript (ES6), 54 bytes

s=>s.replace(r=/\b[^aeiou ]+/g,(_,i)=>s.match(r)[+!i])

Explanation

s=>
  s.replace(
    r=/\b[^aeiou ]+/g,     // r = regex to match consonants
    (_,i)=>s.match(r)[+!i] // replace consonants with the consonants from the other word
  )

Test

var solution = s=>s.replace(r=/\b[^aeiou ]+/g,(_,i)=>s.match(r)[+!i])
<input type="text" id="input" value="plaster man" />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>

\$\endgroup\$
2
  • \$\begingroup\$ Ohh, my bad, I misunderstood. I'll take a look at the mdn docs for match when I get home \$\endgroup\$ Jan 14, 2016 at 22:30
  • \$\begingroup\$ The +!i trick is a nice solution. +1 \$\endgroup\$ Jan 22, 2016 at 2:30
11
\$\begingroup\$

Python 3, 108 101 99 bytes

(No use of regex)

This function expects input via 2 arguments, e.g. f('blushing','crow'). Returns the new words in a tuple.

S=lambda s,p="":s[0]in"aeiou"and(p,s)or S(s[1:],p+s[0])
def f(x,y):a,b=S(x);c,d=S(y);return c+b,a+d

There are a lot of regex solutions, so I wanted to write something that didn't use Python's re library.

How it works

The only complicated part is the lambda expression S (the abbreviation means "Split before the first vowel"). It recursively "iterates" over the given word, moving one character at a time from the beginning of s (which starts with the whole word) to the end of p (which starts empty). At the first vowel encountered it returns (p,s), i.e. (prefix, suffix). Notice that that is the wrong order compared to the parameters!

I thought it made more sense for the returned order to be prefix, then suffix (because generally a prefix goes before a suffix). This order might make the a,b=S(x) code slightly easier to read.

But I had no choice of order in the lambda's parameters, so I couldn't define p before s. The first parameter, s, had to take the entire word because p had a default value, and default parameters go last. Doing that, I didn't need to call the function S with an empty string twice, and a few bytes could be saved. However, perhaps it was simply a bad decision to return prefix/suffix in the opposite order as it was used within the lambda expression.

As for the choice of lambda expression over function, it takes more bytes to say def S(s,p=""):return than S=lambda s,p="":. I can make that choice because Python has short-circuit evaluation, and the ternary operator. However, I cannot adequately explain how I used short-circuits; it's hard to reason about.


This is my first answer. I hope I did this correctly, and that there's value to posting a solution that cannot win.

Edits: Thank-you commenters: Reduced the byte count a bit, twice, and removed unnecessary info. Attempted to improve writing. Hopefully made no mistakes.

\$\endgroup\$
5
  • \$\begingroup\$ welcome to ppcg, great first answer :) just fyi, most programs on this site don't have a trailing newline, so you don't have to mention it (in the rare cases when it is necessary, that's when people mention it) \$\endgroup\$ Jan 18, 2016 at 4:50
  • 3
    \$\begingroup\$ Welcome to Programming Puzzles & Code Golf! 1. You don't have to worry about the input format. The challenge explicitly says that you can take a list. 2. Per the defaults mentioned in the tag wiki, you can submit either full programs or functions to code golf challenges. For this particular problem, a function should be 7 bytes shorter. \$\endgroup\$
    – Dennis
    Jan 18, 2016 at 6:24
  • 4
    \$\begingroup\$ Regarding the last sentence, "I hope [...] there's value to posting a solution that cannot win." There most certainly is! We're all here to have fun and contribute and learn from each other. I find this answer particularly clever as the more obvious solution is to use regular expressions. Very nice work! \$\endgroup\$
    – Alex A.
    Jan 18, 2016 at 9:07
  • \$\begingroup\$ A excellent first answer. It's quite similar to what I came up with for non-regex. You had a good thought about using short-circuiting logical expressions, and it turns out they can shorten the expression, though perhaps you'd like to think yourself about how to do that. \$\endgroup\$
    – xnor
    Jan 20, 2016 at 5:49
  • \$\begingroup\$ I really like the fact you used a recursive solution. Very elegantly implemented! \$\endgroup\$
    – Ogaday
    Jan 21, 2016 at 1:18
9
\$\begingroup\$

C#6, 115 bytes

string S(string a)=>System.Text.RegularExpressions.Regex.Replace(a,"([^aeiou]*)(.*) ([^aeiou]*)(.*)","$3$2 $1$4");

It's just a pain the namespace for regex is so long.

\$\endgroup\$
3
  • 2
    \$\begingroup\$ My gosh that is verbose. \$\endgroup\$ Jan 14, 2016 at 2:34
  • 4
    \$\begingroup\$ System.Text.RegularExpressions.Regex.Replace 44 characters! +1 because that must be some kind of record. \$\endgroup\$ Jan 14, 2016 at 10:01
  • 2
    \$\begingroup\$ ...and now you have 44 problems. ;) \$\endgroup\$ Jan 15, 2016 at 21:04
9
\$\begingroup\$

CJam, 27 24 22 bytes

2{l_{"aeiou"&}#/(N\}*o

I/O is one word per line. Try it online!

How it works

2{                 }*   Do the following twice:
  l                       Read a line from STDIN.
   _                      Push a copy.
    {"aeiou"&}#           Find the index of the first character that has a non-
                          empty intersection with the string "aeiou".
               /          Split the string into chunks of that size.
                (         Shift out the first chunk, i.e., all leading consonants.
                 N\       Swap the shifted out chunk with a linefeed.
                     o  Print the topmost stack item.
\$\endgroup\$
0
9
\$\begingroup\$

Perl, 33 bytes

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

The above code is 32 bytes long and requires the -p switch (+1 byte).

The substitution is very similar to the one @DigitalTrauma's Retina answer, but this answer takes advantage of PCRE's recursive subpatterns.

Try it online on Ideone.

\$\endgroup\$
8
\$\begingroup\$

Retina, 34

([^aeiou]+)(.+ )([^aeiou]+)
$3$2$1

Try it online.

\$\endgroup\$
8
\$\begingroup\$

JavaScript ES6, 93 58 52 bytes

Saved 6 bytes thanks to ETHProductions!

x=>x.replace(/([^aeiou]+)(.+ )([^aeiou]+)/,"$3$2$1")

Test it! (ES6 only)

F=x=>x.replace(/([^aeiou]+)(.+ )([^aeiou]+)/,"$3$2$1");

console.log=_=>u.innerHTML+=_;

console.log(`plaster man -> master plan
blushing crow -> crushing blow
litigating more -> mitigating lore
strong wrangler -> wrong strangler
def ghi -> ghef di`.split`\n`.map(e=>(e=e.split` -> `,`${e[0]} => ${e[1]} ||> `+(F(e[0])==e[1]))).join`<br>`);
html { font-family: Consolas, monospace; }
<div id=u></div>

\$\endgroup\$
4
  • \$\begingroup\$ I was just about to click post answer on my 58 byte solution when you made this edit haha \$\endgroup\$
    – user81655
    Jan 14, 2016 at 2:40
  • \$\begingroup\$ @user81655 Oh, sorry that it happened like that. \$\endgroup\$ Jan 14, 2016 at 12:00
  • \$\begingroup\$ You don't need the fourth capturing group or the $4 at all ;) \$\endgroup\$ Jan 14, 2016 at 13:01
  • \$\begingroup\$ @ETHproductions Oh, yeah! Thanks! \$\endgroup\$ Jan 14, 2016 at 13:11
7
\$\begingroup\$

C, 255 201 199 bytes

I don't see a lot of C answers around here, so enjoy; Also, first time golfing, suggestions and critique are welcome.

#define S(w,p)p=strpbrk(w,"aeiou")-w
#define c ;strcpy(r
#define l c+strlen(v[1])+b+1
main(int q,char**v){char r[64],S(v[1],a),S(v[2],b)c,v[2])c+b,v[1]+a);strcat(r," ")l-a,v[1])l,v[2]+b);puts(r);}

If main() is not required we can save 24 bytes, getting to 179 bytes

#define S(w,p)p=strpbrk(w,"aeiou")-w
#define c ;strcpy(r
#define l c+strlen(x)+b+1
s(char*x,char*y){char r[64],S(x,a),S(y,b)c,y)c+b, x+a);strcat(r," ")l-a,x)l,y+b);puts(r);}

Ungolfed:

void spoonerise(char* w1, char* w2)
{
    char rt[64];

    int p1 = strpbrk(w1, "aeiou")-w1;
    int p2 = strpbrk(w2, "aeiou")-w2;

    strcpy(rt, w2);
    strcpy(rt+p2, w1+p1);

    strcat(rt, " ");

    strcpy(rt+strlen(w1)+p2+1-p1, w1);
    strcpy(rt+strlen(w1)+p2+1, w2+p2);

    puts(rt);
}

EDIT: Thanks to feersum's suggestion I saved 54 bytes. =D

\$\endgroup\$
3
  • \$\begingroup\$ I recommend looking into strpbrk. \$\endgroup\$
    – feersum
    Jan 16, 2016 at 19:11
  • \$\begingroup\$ +1 This is a great first answer. Welcome to the site. \$\endgroup\$
    – wizzwizz4
    Jan 16, 2016 at 20:25
  • \$\begingroup\$ Thanks for the recommedation @feersum. And thanks for the welcoming @wizzwizz4! \$\endgroup\$ Jan 16, 2016 at 21:28
6
\$\begingroup\$

sed, 38 characters

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

Using extended regular expression from the Retina solution.

The above is 37 characters long and requires the -r switch (+1 character).

Example:

$ cat input | tee /dev/tty | sed -r 's/([^aeiou]+)(.+ )([^aeiou]+)/\3\2\1/'
plaster man
blushing crow
litigating more
strong wrangler
def ghi
master plan
crushing blow
mitigating lore
wrong strangler
ghef di
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Programming Puzzles & Code Golf! \$\endgroup\$
    – Dennis
    Jan 17, 2016 at 14:28
5
\$\begingroup\$

Python 2, 364 352 269 251 bytes

EDIT: Thanks so much to @Cyoce for helping me golf 83 bytes!

Please help me golf this! Anyway, at least I am the first Python answerer. And I hope I can beat Java, if there ever is a Java answer!

i=input()
f=l=''
A='aeiou'
for j in A:
 I=i[0];J=I.find(j)
 if ~J:
  if f:
   if f>I[0][:J]:f=I[:J];break
  else:f=I[:J]
for j in A:
 Y=i[1];J=Y.find(j)
 if ~J:
  if l:
   if l>Y[:J]:l=Y[:J];break
  else:l=Y[:J]
print I.replace(f,l,1),Y.replace(l,f,1)

Try it here

\$\endgroup\$
3
  • 6
    \$\begingroup\$ -1 for not making an attempt to golf this beyond single-character variables \$\endgroup\$
    – user45941
    Jan 14, 2016 at 3:06
  • \$\begingroup\$ @Mego I promise I am working on that ASAP. Right now. But I am working on a regex version. \$\endgroup\$
    – TanMath
    Jan 14, 2016 at 3:07
  • \$\begingroup\$ @Mego please see edit. \$\endgroup\$
    – TanMath
    Jan 14, 2016 at 3:23
5
\$\begingroup\$

Japt, 26 25 bytes

Fortunately, I added a vowel class to Japt's regex features a few days ago. Unfortunately, I didn't add a non-vowel class or a way around the double backslashes in regex strings.

#¿s4 £Uf"[^\\v]+|.+
?" gX

The ¿ should be the raw char U+0093. Input is a multi-line string, one word/line. Try it online!

EDIT: I've now added the non-vowel class \V and a way around \\ (with %), so this code now works for 21 bytes: (Try it online)

#¿s4 £Uf"%V+|.+
?" gX

How it works

                     // Implicit: U = input string
#¿s4                 // Convert the char code (147) into a base-4 string "2103".
     £               // Map each char X in this string to:
      Uf"[^\\v]+|.+  //  Match each group in U of non-vowels or non-newlines,
?"                   //  with an optional trailing newline.
   gX                //  Get the item at position X in the resulting array.
                     // Implicit: output last expression

Old version (26 bytes):

UrA="\\b[^\\v ]+"@UfA gÂ!Y

Try it online!

How it works

UrA="\\b[^\\v ]+"@UfA gÂ!Y  // Implicit: U = input string
  A="\\b[^\\v ]+"           // Set variable A to this regex string, which matches
                            // a word boundary followed by one or more non-vowels.
UrA              @          // Take U and replace each match X of A and its index Y with:
                  UfA       //  Take U.match(A).
                      gÂ!Y  //  Get the item at index ~~!Y (converts 0 to 1, anything else to 0).
                            // Implicit: output last expression
\$\endgroup\$
1
  • \$\begingroup\$ I wish mainstream languages had a vowel meta for regexes! \$\endgroup\$
    – CJ Dennis
    Jan 16, 2016 at 13:53
4
\$\begingroup\$

Python 3, 100 (or 99) bytes

import re
def f(*g):a,b=[re.split("[aeiou]",r)[0] for r in g];return b+g[0][len(a):],a+g[1][len(b):]

Played with a few versions but can't seem to get it below. Can get it down 99 bytes by using def f(g) instead so it takes a list of strings rather than two seperate strings, but I prefer the two arg roue.

The alternative is equal length:

import re
s=re.split
def f(x,y):v="[aeiou]";a,b=s(v,x)[0],s(v,y)[0];return b+x[len(a):],a+y[len(b):]

I tried replace, like @TanMath uses, but I couldn't get it any shorter. Also, TanMath can get his answer shorter by a byte by also using "[aeiou]" instead of "[aeiou]+" because we only need to match the single instances. Finally, the implementation of input() seems to have changed between py2 and py3 - it automatically evaluates stdin as a string.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Presumably you mean s=re.split in the alternative? \$\endgroup\$
    – xnor
    Jan 16, 2016 at 4:13
  • \$\begingroup\$ Yes! Definitely. This is my first time golfing ever, so any feedback and advice is appreciated. \$\endgroup\$
    – Ogaday
    Jan 16, 2016 at 15:01
  • 1
    \$\begingroup\$ 1. The question explicitly allows to take the two strings as a list, so there seems to be no good reason for the * in *g. 2. The second version can be golfed down to lambda x,y,s=lambda s:re.split("[aeiou]",s)[0]:(s(y)+x[len(s(x)):],s(x)+y[len(s(y)):]). \$\endgroup\$
    – Dennis
    Jan 16, 2016 at 15:54
  • \$\begingroup\$ Thanks @Dennis, that does indeed work, nice refactoring. Interesting that the brackets are needed, and you don't need to pass s as an arg to the second lambda do you? That solution gives me 98 bytes, with a leading import statement and f=. \$\endgroup\$
    – Ogaday
    Jan 18, 2016 at 18:37
  • 1
    \$\begingroup\$ No, s is a default argument, so you don't have to specify it. An unnamed lambda is an acceptable submission; f= is not required. \$\endgroup\$
    – Dennis
    Jan 18, 2016 at 18:50
3
\$\begingroup\$

C#6, 165 bytes

string S(string a,string b){int i=V(a),j=V(b);return b.Remove(j)+a.Substring(i)+" "+a.Remove(i)+b.Substring(j);}int V(string s)=>s.IndexOfAny("aeiou".ToCharArray());

Expanded:

string S(string a,string b){
    int i=V(a),
        j=V(b);
    return b.Remove(j)+a.Substring(i)+" "+a.Remove(i)+b.Substring(j);
}
int V(string s)=>s.IndexOfAny("aeiou".ToCharArray());
\$\endgroup\$
3
  • \$\begingroup\$ This is pretty old, but "aeiou".ToCharArray() can be 'a','e','i','o','u' for -2 bytes \$\endgroup\$
    – Gymhgy
    Mar 28, 2019 at 21:35
  • \$\begingroup\$ No, @EmbodimentofIgnorance , IndexOfAny it doesn't take params, so it would need to be new[]{'a','e','i','o','u'} \$\endgroup\$ Mar 28, 2019 at 23:32
  • \$\begingroup\$ Ah, my mistake, I thought IndexOfAny is a params method. Anyways, great answer \$\endgroup\$
    – Gymhgy
    Mar 29, 2019 at 2:47
3
\$\begingroup\$

𝔼𝕊𝕄𝕚𝕟, 24 chars / 42 bytes

ïē/⟮(⁅ᶌ]+)⟯(.+ )Ⅰ/,`⑶⑵⑴`

Try it here (Firefox only).

If you need help comprehending this, this translates to ES6 as

input.replace(/([^aeiou]+)(.+ )([^aeiou]+)/g,'$3$2$1')
\$\endgroup\$
5
  • \$\begingroup\$ What language is this in? I'm getting box-characters for even that. \$\endgroup\$ Jan 14, 2016 at 17:21
  • \$\begingroup\$ @JesseWilliams It's called ESMin. \$\endgroup\$ Jan 14, 2016 at 17:46
  • \$\begingroup\$ It would be nice if the interperator had something like the Japt one where it shows you the js the 𝔼𝕊𝕄𝕚𝕟 becomes \$\endgroup\$ Jan 17, 2016 at 13:34
  • 1
    \$\begingroup\$ Compiled JS is logged in the JS console when the code is run. \$\endgroup\$ Jan 17, 2016 at 17:12
  • \$\begingroup\$ @MamaFunRoll should put that somewhere inthe ESMin Readme. \$\endgroup\$
    – Razetime
    Nov 16, 2020 at 2:06
3
\$\begingroup\$

PowerShell, 52 bytes

"$args "-replace('(.*?)([aeiou]\S+) '*2),'$3$2 $1$4'

e.g. 
PS C:\scripts\> .\Spoonerise.ps1 'blushing crow'
crushing blow

It's a regex replace with four capture groups; with:

  • String multiplication to expand:
    • ('(.*?)([aeiou]\S+) '*2) to '(.*?)([aeiou]\S+) (.*?)([aeiou]\S+) '
  • The "$args " forces the args array into a string, and adds a trailing space so the trailing space in the regex won't break it.
\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6), 120 107 102 101 99 92 bytes

  • Thanks downgoat!

This takes into account if the parameters were an object like this, and backward:
var a = {x: "man", y:"plaster"]}

a.b=(e=>e.slice(e.search`[aeiou]`));with(a){c=b(x),d=b(y),x=x.replace(c,d);y=y.replace(d,c)}
\$\endgroup\$
1
  • \$\begingroup\$ .match(/[aeiou]/).index can become: .search`[aeiou]` \$\endgroup\$
    – Downgoat
    Jan 15, 2016 at 5:10
3
\$\begingroup\$

Python, 129 108 105 109 bytes

This program takes in a list of words like this ["master","plan"]

EDIT: Thanks @Volatility

EDIT: Now using re.split

import re
a=re.split
c='[aeiou]+'
i,j=input()
f=a(c,i)[0]
l=a(c,j)[0]
print i.replace(f,l,1),j.replace(l,f,1)

This answer uses regex as most of them do.

Try it here

\$\endgroup\$
8
  • \$\begingroup\$ Note that str.replace replaces all instances of a substring, so you want to limit it to one replacement by having .replace(f,l,1). However, you can save a bunch by using i,j=input(), and rebinding re.findall and '[^aeiou]+' to single character variables. \$\endgroup\$
    – Volatility
    Jan 14, 2016 at 4:06
  • \$\begingroup\$ This doesn't work as it is; even two one-letter words will give you three characters, and you're trying to unpack input() into two variables. Did you mean i,j=input().split() (and raw_input() in Python 2)? \$\endgroup\$ Jan 16, 2016 at 4:03
  • 1
    \$\begingroup\$ @BlacklightShining the word needs to have at least one vowel and one consonant. The input takes in a list of the strings so i is the first word and j is the second. \$\endgroup\$
    – TanMath
    Jan 16, 2016 at 4:26
  • \$\begingroup\$ @TanMath as far as i know that is allowed by default, but you should probably say in the answer somewhere that it's required \$\endgroup\$ Jan 16, 2016 at 4:26
  • \$\begingroup\$ This replaces too much. "sass","bit" -> "babb", "sit". \$\endgroup\$
    – xnor
    Jan 16, 2016 at 4:40
3
\$\begingroup\$

Java 8, 343 Bytes

Here you have your first Java-Answer. Not that experienced with golfing, so every suggestion is appreciated!

java.util.function.Function;public class C{public static void main(String[] a){Function<String, Integer>f=s->{for(int i=0;i<s.length();++i)if("aeiou".contains(s.substring(i,i+1)))return i;return 0;};int i1=f.apply(a[0]),i2=f.apply(a[1]);System.out.println(a[1].substring(0,i2)+a[0].substring(i1)+" "+a[0].substring(0,i1)+a[1].substring(i2));}}

Ungolfed:

public class SpooneriseWords {
    public static void main(String[] args)
    {       
        Function<String, Integer> f = s -> {
            for(int i = 0; i < s.length(); ++i)
                if("aeiou".contains(s.substring(i, i + 1))) 
                    return i;
            return 0;
        };

        int i1 = f.apply(args[0]);
        int i2 = f.apply(args[1]);
        System.out.println(args[1].substring(0, i2) + args[0].substring(i1));
        System.out.println(args[0].substring(0, i1) + args[1].substring(i2));
    }
}
\$\endgroup\$
6
  • \$\begingroup\$ What's java.util.function.Function? I highly doubt it needs to be there, unless you mean import, but drop the import because you only refer to it once. Change public class C{public static void Main(String[] a) to interface C{void Main(String[]a) \$\endgroup\$
    – cat
    Mar 5, 2016 at 23:34
  • \$\begingroup\$ Function<String, Integer> doesn't need whitespace \$\endgroup\$
    – cat
    Mar 5, 2016 at 23:34
  • \$\begingroup\$ change the for loop from for(int i=0;i<s.length();++i)if("aeiou".contains(s.substring(i,i+1)))return i; to for(int i=0;i++<s.length();if("aeiou".contains(s.substring(i,i+1))){return i;}) \$\endgroup\$
    – cat
    Mar 5, 2016 at 23:36
  • \$\begingroup\$ i1 is a terrible, far too long varname. \$\endgroup\$
    – cat
    Mar 5, 2016 at 23:37
  • \$\begingroup\$ That is, change Function<String, Integer> to java.util.function.Function<String,Integer> and drop the import \$\endgroup\$
    – cat
    Mar 5, 2016 at 23:39
3
\$\begingroup\$

Octave, 96 bytes

Thanks to Octave's inline assignments and 'index-anywhere' functionality, this entire thing is just the definition of a single, anonymous function. Basically, we reconstruct the spoonerized string while storing the cut-off points in a and b. I'm especially happy with the inline f function, which finds the cut-off point, and prevented me from having to use the whole 'find(ismember(a,b),1)' thing twice. Also, no regex :).

@(p,q)[q(1:(a=(f=@(m)find(ismember(m,'aeoui'),1))(q))-1),p(b=f(q):end),32,p(1:b-1),q(a:end)];
\$\endgroup\$
3
\$\begingroup\$

Python (no regexes), 85 bytes

t=lambda s:s[1]in'aeiou'or-~t(s[1:])
lambda a,b:(b[:t(b)]+a[t(a):],a[:t(a)]+b[t(b):])

Sample run:

>>> t=lambda s:s[1]in'aeiou'or-~t(s[1:])
>>> lambda a,b:(b[:t(b)]+a[t(a):],a[:t(a)]+b[t(b):])
<function <lambda> at 0x7f495e534398>
>>> _('plaster', 'man')
('master', 'plan')

t is a recursive function that computes the index of the earliest vowel after the first character in its argument s. If the second character s[1] is a vowel, it evaluates to True, which has int value 1. Otherwise it makes a recursive call with the first character removed, and adds 1 to the resulting index using -~ (two’s complement of one’s complement). Finally, the results of t are used as indices for string slicing to compute the spoonerism.

\$\endgroup\$
2
\$\begingroup\$

TeaScript, 27 bytes

xg/(\w+)(.+ )(\w+)/,"$3$2$1

\w is actually [^aeiou].

\$\endgroup\$
2
  • \$\begingroup\$ Hang on, you changed the default \w regex meta to [^aeiou]? Why? \$\endgroup\$ Jan 21, 2016 at 1:45
  • \$\begingroup\$ @ETHproductions when I was creating the custom char classes. I forgot that \w was already used by JavaScript. I'll change it back soon \$\endgroup\$
    – Downgoat
    Jan 21, 2016 at 1:51
2
\$\begingroup\$

PowerShell, 61 bytes

"$args"-replace'([^aeiou]+)(.*)\s([^aeiou]+)(.*)','$3$2 $1$4'

Uses regex to swap the first non-vowel characters of each word

\$\endgroup\$
2
\$\begingroup\$

Elixir, 143 117 Bytes

s=fn w->String.split_at(w,elem(hd(Regex.run(~r/[aeiou]/,w,return: :index)),0))end
{v,w}=s.(a)
{x,y}=s.(b)
[x<>w,v<>y]

Split up the two strings (a, b) on the first vowel and construct new strings to return.

EDIT: Got a few bytes off by using pattern matching instead of clunky elem calls to get the values out of the tuples.

\$\endgroup\$
2
\$\begingroup\$

Java, 147 Bytes

I'm assuming just a function is fine too.

String s(String[]i){String r="[aeiou]",f=i[0].split(r)[0],s=i[1].split(r)[0];return s+i[0].substring(f.length())+" "+f+i[1].substring(s.length());}

split(regex) unfortunately consumes the delimiter, which means that I have to use substring to get the suffixes.

\$\endgroup\$
0
2
\$\begingroup\$

Pyth, 30 28 bytes

Takes input and gives output as a list of the two words.

ACm,Kh:d"[aeiou]"3.-dKQ+V_GH

Try it online.

\$\endgroup\$
1
  • \$\begingroup\$ I think you're looking for ACm,Kh:d"[aeiou]"3.-dKQ+V_GH. A assigns a two-element list to G and H, and C transposes. There may be something even better. \$\endgroup\$
    – lirtosiast
    Jan 21, 2016 at 3:29
2
\$\begingroup\$

Brainfuck, 141 bytes

,[[[<+>>+<-]----[>-----<--]>+[++++++[++++++[++++[++++[,>]]]]]<]<[>+<-]>>>+[,[[<+
>>+<-]++++[>--------<-]]>]>,]<<<<[[<]<[<]>[.,+>]+<]>[-[+.,]>]

Formatted:

,
[
  [
    [<+> >+<-]
    ----[>-----<--]>+
    [
      not u
      ++++++
      [
        not o
        ++++++
        [
          not i
          ++++
          [
            not e
            ++++
            [
              not a
              ,>
            ]
          ]
        ]
      ]
    ]
    <
  ]
  <[>+<-]>>>+
  [
    ,
    [
      [<+> >+<-]
      ++++[>--------<-]
    ]
    >
  ]
  >,
]
<<<<
[
  [<]<[<]
  >[.,+>]
  +<
]
>[-[+.,]>]

Expects the two words separated by a space, with or without a trailing newline.

Try it online.

This takes the input and stores it on the tape with three zero cells added: one before the first vowel of each word, and one after the space between the two words. For example, plaster man becomes:

pl\x00aster \x00m\x00an

The three fragments m, aster, and pl are then printed by looping backwards through the tape while creating dummy \x01 cells, and the final an is printed by going forwards and ignoring the dummy cells.

\$\endgroup\$

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.