Spoonerise words

50

4

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.

xnor

Posted 2016-01-14T01:56:42.280

Reputation: 115 687

What if a word starts with a vowel, such as "snoozing otter"? – Hand-E-Food – 2016-01-14T05:59:53.620

4The words start with consonants. – xnor – 2016-01-14T06:01:43.927

21Answer should be "oozing snotter" imo~ – Patrick Roberts – 2016-01-14T19:45:37.260

3@PatrickRoberts I agree, but this makes the challenge a bit simpler. – xnor – 2016-01-14T21:24:40.127

Well for some regexes you can just replace the + with * and add a ^ at the beginning to negate the greedy search – Patrick Roberts – 2016-01-14T22:02:45.663

I wrote almost the exact same challenge also with a clearer and more stable spec almost a year ago. Why is it appropriate for this challenge to stay open and mine is a dupe?

– James – 2016-01-15T01:45:43.767

@DJMcMayhem Sorry, that is frustrating. I wasn't aware of your question and didn't find it when searching. I think nobody was aware of the option to close the old one as a dupe until Martin Büttner's well-received post in October. I definitely wasn't. I believe this is the first challenge written specifically to try to supersede an old challenge.

– xnor – 2016-01-15T04:00:43.963

1

Not very on topic, but a nice example snow flake -> flow snake

– flawr – 2016-01-17T13:02:19.650

1fast lucks and coy bunts are not allowed to participate – Denham Coote – 2016-01-18T11:44:01.310

1Mission Failed -> Fission Mailed (Warning: TVTropes link detected) – Bojidar Marinov – 2016-01-19T14:22:20.707

1@xnor I think the first challenge written specifically for that purpose was the cat catalogue, but I think that slipped through the cracks before there was an actual consensus. ;) (It was posted a day after that meta post, but had been planned before, and I don't think the meta post would have had the current score back then.) – Martin Ender – 2016-01-19T14:55:21.477

Answers

50

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.

orlp

Posted 2016-01-14T01:56:42.280

Reputation: 37 067

... oh, duh, didn't think of that. Kept getting thrown off by v being inclusive and trying to select from the vowel back. – Doorknob – 2016-01-14T02:20:14.847

10As a casual vim user, I kept being amazed as I typed each successive command – Aaron – 2016-01-14T14:35:44.940

4<CR> means carriage return (old typewriter term!), also known as Enter – Kai Carver – 2016-01-14T18:50:04.493

22

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
>[.>>]

undergroundmonorail

Posted 2016-01-14T01:56:42.280

Reputation: 5 897

This counts y as a vowel, but the question says it's not. (nye cat -> ce nyat) – Loovjo – 2016-01-22T13:11:58.033

1@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. – undergroundmonorail – 2016-01-22T13:18:25.183

17

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

Doorknob

Posted 2016-01-14T01:56:42.280

Reputation: 68 138

11I do this in Insert mode, right? – Alex A. – 2016-01-15T06:57:51.977

5@AlexA. ಠ_ಠ​​​​ – Doorknob – 2016-01-15T12:12:39.267

@AlexA. Insert mode would be an extra keystroke :)~ – pydsigner – 2016-01-15T20:10:01.753

@AlexA. Insert mode? Did you mean insert command? – Blacklight Shining – 2016-01-16T03:43:45.910

1@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. – Alex A. – 2016-01-16T04:22:50.000

13

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.

Dennis

Posted 2016-01-14T01:56:42.280

Reputation: 196 637

1Congrats on the bounty, for bringing the regex magic to Python with a very efficient regex. Nice explanation too. – xnor – 2016-01-23T08:22:01.513

11

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>

user81655

Posted 2016-01-14T01:56:42.280

Reputation: 10 181

Ohh, my bad, I misunderstood. I'll take a look at the mdn docs for match when I get home – Patrick Roberts – 2016-01-14T22:30:10.980

The +!i trick is a nice solution. +1 – ETHproductions – 2016-01-22T02:30:37.180

10

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.

N Beyrich

Posted 2016-01-14T01:56:42.280

Reputation: 101

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) – undergroundmonorail – 2016-01-18T04:50:47.443

3

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.

– Dennis – 2016-01-18T06:24:28.640

4Regarding 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! – Alex A. – 2016-01-18T09:07:22.933

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. – xnor – 2016-01-20T05:49:29.087

I really like the fact you used a recursive solution. Very elegantly implemented! – Ogaday – 2016-01-21T01:18:41.047

9

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.

Hand-E-Food

Posted 2016-01-14T01:56:42.280

Reputation: 7 912

2My gosh that is verbose. – Conor O'Brien – 2016-01-14T02:34:27.670

4System.Text.RegularExpressions.Regex.Replace 44 characters! +1 because that must be some kind of record. – Level River St – 2016-01-14T10:01:22.720

2...and now you have 44 problems. ;) – Mason Wheeler – 2016-01-15T21:04:27.170

9

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.

Dennis

Posted 2016-01-14T01:56:42.280

Reputation: 196 637

9

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.

Dennis

Posted 2016-01-14T01:56:42.280

Reputation: 196 637

8

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>

Conor O'Brien

Posted 2016-01-14T01:56:42.280

Reputation: 36 228

I was just about to click post answer on my 58 byte solution when you made this edit haha – user81655 – 2016-01-14T02:40:07.957

@user81655 Oh, sorry that it happened like that. – Conor O'Brien – 2016-01-14T12:00:41.133

You don't need the fourth capturing group or the $4 at all ;) – ETHproductions – 2016-01-14T13:01:57.860

@ETHproductions Oh, yeah! Thanks! – Conor O'Brien – 2016-01-14T13:11:31.733

8

Retina, 34

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

Try it online.

Digital Trauma

Posted 2016-01-14T01:56:42.280

Reputation: 64 644

7

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

Lince Assassino

Posted 2016-01-14T01:56:42.280

Reputation: 111

I recommend looking into strpbrk. – feersum – 2016-01-16T19:11:19.250

+1 This is a great first answer. Welcome to the site. – wizzwizz4 – 2016-01-16T20:25:03.150

Thanks for the recommedation @feersum. And thanks for the welcoming @wizzwizz4! – Lince Assassino – 2016-01-16T21:28:29.647

6

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

TanMath

Posted 2016-01-14T01:56:42.280

Reputation: 1 431

5-1 for not making an attempt to golf this beyond single-character variables – Mego – 2016-01-14T03:06:20.857

@Mego I promise I am working on that ASAP. Right now. But I am working on a regex version. – TanMath – 2016-01-14T03:07:11.967

@Mego please see edit. – TanMath – 2016-01-14T03:23:03.017

5

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

ETHproductions

Posted 2016-01-14T01:56:42.280

Reputation: 47 880

I wish mainstream languages had a vowel meta for regexes! – CJ Dennis – 2016-01-16T13:53:43.933

4

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.

Ogaday

Posted 2016-01-14T01:56:42.280

Reputation: 471

1Presumably you mean s=re.split in the alternative? – xnor – 2016-01-16T04:13:42.127

Yes! Definitely. This is my first time golfing ever, so any feedback and advice is appreciated. – Ogaday – 2016-01-16T15:01:14.177

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)):]).
  • < – Dennis – 2016-01-16T15:54:08.700

    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=. – Ogaday – 2016-01-18T18:37:23.930

    1No, s is a default argument, so you don't have to specify it. An unnamed lambda is an acceptable submission; f= is not required. – Dennis – 2016-01-18T18:50:08.563

    4

    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
    

    Zsolt

    Posted 2016-01-14T01:56:42.280

    Reputation: 171

    Welcome to Programming Puzzles & Code Golf! – Dennis – 2016-01-17T14:28:53.473

    3

    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());
    

    Hand-E-Food

    Posted 2016-01-14T01:56:42.280

    Reputation: 7 912

    This is pretty old, but "aeiou".ToCharArray() can be 'a','e','i','o','u' for -2 bytes – Embodiment of Ignorance – 2019-03-28T21:35:03.587

    No, @EmbodimentofIgnorance , IndexOfAny it doesn't take params, so it would need to be new[]{'a','e','i','o','u'} – Hand-E-Food – 2019-03-28T23:32:24.420

    Ah, my mistake, I thought IndexOfAny is a params method. Anyways, great answer – Embodiment of Ignorance – 2019-03-29T02:47:56.987

    3

    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)}
    

    Quill

    Posted 2016-01-14T01:56:42.280

    Reputation: 576

    .match(/[aeiou]/).index can become: .search\[aeiou]`` – Downgoat – 2016-01-15T05:10:53.180

    3

    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

    TanMath

    Posted 2016-01-14T01:56:42.280

    Reputation: 1 431

    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. – Volatility – 2016-01-14T04:06:52.440

    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)? – Blacklight Shining – 2016-01-16T04:03:35.377

    1@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. – TanMath – 2016-01-16T04:26:19.090

    @TanMath as far as i know that is allowed by default, but you should probably say in the answer somewhere that it's required – undergroundmonorail – 2016-01-16T04:26:48.560

    This replaces too much. "sass","bit" -> "babb", "sit". – xnor – 2016-01-16T04:40:58.510

    @xnor fixed now – TanMath – 2016-01-16T04:43:44.443

    @downvoters, why? – TanMath – 2016-01-16T04:54:41.987

    You should combine your two Python answers into a single post then delete the other, imho. – mbomb007 – 2016-01-18T23:07:13.950

    3

    , 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')
    

    Mama Fun Roll

    Posted 2016-01-14T01:56:42.280

    Reputation: 7 234

    What language is this in? I'm getting box-characters for even that. – Jesse Williams – 2016-01-14T17:21:51.490

    @JesseWilliams It's called ESMin.

    – ETHproductions – 2016-01-14T17:46:05.397

    It would be nice if the interperator had something like the Japt one where it shows you the js the becomes – Generic User – 2016-01-17T13:34:34.100

    Compiled JS is logged in the JS console when the code is run. – Mama Fun Roll – 2016-01-17T17:12:34.487

    3

    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.

    TessellatingHeckler

    Posted 2016-01-14T01:56:42.280

    Reputation: 2 412

    3

    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));
        }
    }
    

    Denker

    Posted 2016-01-14T01:56:42.280

    Reputation: 6 639

    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) – cat – 2016-03-05T23:34:19.203

    Function<String, Integer> doesn't need whitespace – cat – 2016-03-05T23:34:41.657

    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;}) – cat – 2016-03-05T23:36:50.363

    i1 is a terrible, far too long varname. – cat – 2016-03-05T23:37:30.753

    That is, change Function<String, Integer> to java.util.function.Function<String,Integer> and drop the import – cat – 2016-03-05T23:39:52.520

    the for loop can drop the int i = 0; in place of int i; since things are initialised to zero – cat – 2016-03-05T23:50:40.117

    3

    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)];
    

    Sanchises

    Posted 2016-01-14T01:56:42.280

    Reputation: 8 530

    2

    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.

    Luke

    Posted 2016-01-14T01:56:42.280

    Reputation: 5 091

    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. – lirtosiast – 2016-01-21T03:29:20.753

    2

    TeaScript, 27 bytes

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

    \w is actually [^aeiou].

    Downgoat

    Posted 2016-01-14T01:56:42.280

    Reputation: 27 116

    Hang on, you changed the default \w regex meta to [^aeiou]? Why? – ETHproductions – 2016-01-21T01:45:42.727

    @ETHproductions when I was creating the custom char classes. I forgot that \w was already used by JavaScript. I'll change it back soon – Downgoat – 2016-01-21T01:51:37.570

    2

    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.

    srecnig

    Posted 2016-01-14T01:56:42.280

    Reputation: 171

    2

    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.

    ECS

    Posted 2016-01-14T01:56:42.280

    Reputation: 361

    2

    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.

    Anders Kaseorg

    Posted 2016-01-14T01:56:42.280

    Reputation: 29 242

    1

    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.

    Mitch Schwartz

    Posted 2016-01-14T01:56:42.280

    Reputation: 4 899

    1

    GNU Awk 4.0, 48 characters

    split($0,a,/\<[^aeiou]+/,s)&&$0=s[2]a[2]s[1]a[3]
    

    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
    

    manatwork

    Posted 2016-01-14T01:56:42.280

    Reputation: 17 865

    1

    PowerShell, 61 bytes

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

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

    Mathias R. Jessen

    Posted 2016-01-14T01:56:42.280

    Reputation: 121

    1

    Lua, 80 bytes

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

    You can test it here.

    Ungolfed:

    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)
    end
    

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

    DavisDude

    Posted 2016-01-14T01:56:42.280

    Reputation: 293

    Is some of the whitespace at parentheses removable? – ETHproductions – 2016-01-21T01:23:00.870

    Good catch, it is. I always forget to do those things. – DavisDude – 2016-01-21T01:38:54.427

    0

    Python 162

    p,q=raw_input().split()
    a=b=-1
    c=d=0
    v='aeiou'
    while a<0:
     if p[c]in v:
      a=c
     c+=1
    while b<0:
     if q[d]in v:
      b=d
     d+=1
    print " ".join((q[:b]+p[a:],p[:a]+q[b:]))
    

    epson121

    Posted 2016-01-14T01:56:42.280

    Reputation: 171

    0

    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

    Test:

    litigating more
    ans =
    mitigating lore
    
    def ghi
    ans =
    ghef di
    

    brainkz

    Posted 2016-01-14T01:56:42.280

    Reputation: 349

    The spec doesn't require a single string as input, so you can probably drop the strsplit part. – Sanchises – 2016-01-20T19:54:08.813

    0

    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.

    xnor

    Posted 2016-01-14T01:56:42.280

    Reputation: 115 687

    In GHC 7.10, replacing map() with the infix <$> saves two bytes. – Anders Kaseorg – 2016-02-04T16:37:09.707

    @AndersKaseorg Thanks, changed it. – xnor – 2016-02-05T20:30:01.667

    0

    PHP 405 325

    Minified:

    <?php
    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:

    <?php
    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);
            ++$loop;
        }
        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;
    

    james

    Posted 2016-01-14T01:56:42.280

    Reputation: 101