Swep tha vowels!

18

1

Note: the title was misspelled intentionally.

Given a string s, swap the first vowel runs of every 2 words. For this challenge, y is considered a vowel.

For example, given an input of "great day sir":

1. Input: "great day sir"
2. Identify pairs of words: "[great day] [sir]" (No word for sir to pair with)
3. Identify the first vowel runs in each word: "[gr[ea]t d[ay]] [s[i]r]"
4. Swap the vowel runs in each pair: "[gr[ay]t d[ea]] [s[i]r]"
5. Return/print: "grayt dea sir"

When there are vowel runs of different lengths, you still swap the whole runs. When a word has more than one vowel runs, you still only swap the first one. When the first or second word of a pair of words does not have a vowel, then you do not swap the vowels for those words.

You may assume that the input only consists of one case of alphabetic letters and the literal space or another constant delimiter.

Standard methods of I/O, standard loopholes apply. Leading/trailing whatevers are okay.

Test cases:

Input -> Output

"great day sir" -> "grayt dea sir"
"ppcg is the best" -> "ppcg is the best" (When there is no vowel to swap, don't swap vowels."
"this is a test case" -> "this is e tast case"
"loooooooooooooong word" -> "long woooooooooooooord"
"great night" -> "grit neaght"
"anything goes" -> "oenything gas"
"qwrtpsdfghjklzxcvbnm aaaaaaaa hi there" -> "qwrtpsdfghjklzxcvbnm aaaaaaaa he thire"
"this is a long test case in case you could not tell" -> "this is o lang tast cese an cise ou cyould net toll"

Comrade SparklePony

Posted 2017-06-13T20:07:54.113

Reputation: 5 784

1

For those who can see deleted posts, the sandbox post was here.

– Comrade SparklePony – 2017-06-13T20:09:02.750

1If the first word has no vowels, is it OK to swap the vowels of the second and third words? Or can vowels only swap between runs of two words? For example, should ppcg is awesome become ppcg is awesome or ppcg as iwesome? – James – 2017-06-13T20:18:40.197

@DJMcMayhem Vowels can only swap between runs of two words. I will edit. – Comrade SparklePony – 2017-06-13T20:21:43.143

I believe the output for this is a long test case in case you could not tell should be this is o lang tast cese an cise ou cyould net toll, since the vowel runs you and ou would be swapped. – Bashful Beluga – 2017-06-13T22:49:50.820

@BashfulBeluga Yep, my mistake. I will fix. – Comrade SparklePony – 2017-06-13T23:00:55.710

Passing the test cases is easy enough but getting this right is trickier than it sounds: https://en.oxforddictionaries.com/explore/is-the-letter-y-a-vowel-or-a-consonant

– gmatht – 2017-06-14T04:41:01.760

I don't think you meant to have the brackets in 1. Input: "gr[ea]t day sir", that confused me when I reread it, since that's not part of the actual input. – Sunny Patel – 2017-06-14T14:17:36.677

Answers

9

V, 42, 41 bytes

ò2Eá
òͨ[aeiouy]«©¨ƒ ƒ©¨[aeiouy]«©/³²±
Íî

Try it online!

Hexdump:

00000000: f232 45e1 0af2 cda8 5b61 6569 6f75 795d  .2E.....[aeiouy]
00000010: aba9 a883 2083 a9a8 5b61 6569 6f75 795d  .... ...[aeiouy]
00000020: aba9 2fb3 b2b1 0acd ee                   ../......

Explanation:

ò       ò                                   " Recursively:
 2E                                         "   Move to the end of two words forward
   á<cr>                                    "   And append a newline

This will put all groups of two words on their own line, for example:

this is
a long
test case
in case
you could
not tell

Now we run some fancy regex-magic:

Í                                           " Globally substitute
 ¨[aeiouy]«©                                "   A vowel (capture group 1)
            ¨<131>                          "   Followed by as few characters as possible, then a space
                   <131>©                   "   Followed by as few characters as possible (capture group 2)
                         ¨[aeiouy]«©        "   Followed by a vowel again
                                    /       " With:
                                     ³²±    "   Capture groups '3', '2', '1'
Í                                           " Remove all:
 î                                          "   Newlines

James

Posted 2017-06-13T20:07:54.113

Reputation: 54 537

Your regex doesn't require the end of a word between your two vowel groups. Try it online!

– nmjcman101 – 2017-06-14T13:50:37.167

@nmjcman101 Are you looking at my old revision? Because that's exactly what I have right now – James – 2017-06-14T13:52:34.427

My TIO link wasn't fixing anything, I just changed the input. It swaps the letters oddly. – nmjcman101 – 2017-06-14T13:53:31.643

@nmjcman101 Ah, I see. Fixed now! – James – 2017-06-14T13:57:55.877

6

Japt, 39 37 bytes

They said it would be ugly, but I didn't listen... and it was:

¸ò ®efQ="%y+" ?Z£XrQZg°T fQP PÃ:ZÃc ¸

Test it online!

Explanation

 ¸  ò ® efQ="%y+" ?Z£    XrQ    Zg° T fQ    P PÃ :ZÃ c ¸
UqS ò mZ{Zef"%y+" ?ZmXYZ{Xr"%y+"Zg++T f"%y+"P P} :Z} c qS
             Implicit: U = input string, such as     "abc def ghi jkl mno"
UqS          Split on spaces, splitting into words.  ["abc","def","ghi","jkl","mno"]
ò            Group into runs of two items.           [["abc","def"],["ghi","jkl"],["mno"]]
mZ{          For each pair Z:
 Zef"%y+"?     If not every item contains a run of vowels (%y = [AEIOUYaeiouy]),
 :Z            return Z.                             [              ["ghi","jkl"]        ]
 ZmXYZ{        Otherwise, for each item X in Z:
  Xr"%y+"        Replace each run of vowels with
  Zg++T           the item at the next index in Z,   [["def","abc"]               ["mno"]]
  f"%y+"P         but only the first run of vowels.  [["e",  "a"  ]               ["o"  ]]
  P              Replace only for the first match.   [["ebc","daf"]               ["mno"]]
 }
}                                                    [["ebc","daf"],["ghi","jkl"],"mno"]]
c            Flatten back into a single array.       ["ebc","def","ghi","jkl","mno"]
qS           Re-join on spaces.                      "ebc daf ghi jkl mno"
             Implicit: output result of last expression

ETHproductions

Posted 2017-06-13T20:07:54.113

Reputation: 47 880

5

JavaScript (ES6), 62 106 98 101 bytes

s=>s.match(/(\w+)( (\w+))?/g).map(m=>m.replace(/([aeiouy]+)(\w* \w*?)([aeiouy]+)/g,'$3$2$1')).join` `

f=
s=>s.match(/(\w+)( (\w+))?/g).map(m=>m.replace(/([aeiouy]+)(\w* \w*?)([aeiouy]+)/g,'$3$2$1')).join` `
;

[
  "great day sir",
  "ppcg is the best",
  "this is a test case",
  "loooooooooooooong word",
  "great night",
  "anything goes",
  "qwrtpsdfghjklzxcvbnm aaaaaaaa hi there",
].map(f).map(s=>console.log(s))

darrylyeo

Posted 2017-06-13T20:07:54.113

Reputation: 6 214

4

Retina, 65 bytes

((\w*?)([aeiouy]+)(\w* \w*?)([aeiouy]+)|(\w+ ))(\w*)
$2$5$4$3$6$7

Try it online! Includes test cases. I wanted to use a conditional group reference but I couldn't get it to work in 66 bytes let alone 65 or less.

Neil

Posted 2017-06-13T20:07:54.113

Reputation: 95 035

4

Retina, 50 bytes

\S+ \S+ 
$&¶
%O$^`(?<=\b[^aeiouy]*)[aeiouy]+
$`
¶

Try it online!

−2 bytes thanks to Martin.

  • First step is splitting each word pair to its own line ( is newline). This allows us to use .* within a pair of words.
  • Next, for each line we find the first vowel block in each word, and sort them by position in descending order.

Kobi

Posted 2017-06-13T20:07:54.113

Reputation: 728

I tried removing the double [aeiouy]+ but couldn't get something economic. – Kobi – 2017-06-14T06:36:04.950

@MartinEnder - Nice one! I couldn't get sorting to work. I tried another version that removed the [aeiouy] duplication, but I can't golf it down. I think It might work nicely with your suggestion: https://tio.run/##VU0xDsIwDNz9Cg8BFTrBXLEyMjBCUUMbkkBISuJSysN4AB8rqUAITras8@nuvCBteT9KlkW/Xac4LLDx8wHJhgvtmi5PJ8m2nU4gY7MFm8NoxXZFFj/ACtg8H9kih76XXnDCincYtIe6LiXqgKQE7kUgIBVZHI4UKZY8CDDuD1Zi63wF7ySrpSLgtovOqEgnAlxaT3WoDlIdT@Z@K697e0b@ASo91Hnx02WG0G8havu@nWuwdI2p0DqKujEv

– Kobi – 2017-06-14T08:24:10.023

3

Python 2, 148 bytes

from re import*
v="([aeiouy]+)"
print sub(r"(\w+)(?: (\w+))?",lambda m:sub(v+"(.* .*?)"+v,lambda g:''.join(g.groups()[::-1]),m.group()),raw_input())

Try it online!

Code Golfing is getting addictive!

Sections off pairs of words, then grabs the 2 groups of vowels and the string in between, reverses the order and uses that as the substitute.

Sunny Patel

Posted 2017-06-13T20:07:54.113

Reputation: 294

3

Haskell, 177 173 171 169 bytes

unwords.s.words
s(x:y:z)=maybe[x,y]id(do(a,b)<-k x;(c,d)<-k y;j[b c,d a])++s z
s x=x
v=(`elem`"aeiouy")
j=Just
k s=do(a,(x:y,r))<-j$span v<$>break v s;j(x:y,\n->a++n++r)

Try it online!

This is a direct shortening of the following naïve solution, so there should something much better around here:

swapvowels :: String -> String
swapvowels = unwords . swapPairs . words

swapPairs :: [String] -> [String]
swapPairs (word1:word2:rest) =
   case (,) <$> extractVowels word1 <*> extractVowels word2 of
     Just ((vowels1, rebuild1), (vowels2, rebuild2))
       -> [rebuild1 vowels2, rebuild2 vowels1] ++ swapPairs rest
     Nothing -> [word1,word2] ++ swapPairs rest
swapPairs rest = rest

extractVowels :: String -> Maybe (String, String -> String)
extractVowels s = do
    let isVowel l = l `elem` "aeiouy"
    (a,b) <- Just $ break isVowel s 
    (w@(_:_),r) <- Just $ span isVowel b 
    return (w, \n -> a ++ n ++ r)

bartavelle

Posted 2017-06-13T20:07:54.113

Reputation: 1 261

2

Java (OpenJDK 8), 363 304+25 bytes

-34 bytes thanks to @KevinCruijssen

Golfed:

l->{String s[]=l.split(" "),a,b;Pattern p=Pattern.compile("[aeiouy]+");for(int i=0;i<s.length-1;i+=2){Matcher m=p.matcher(s[i]),n=p.matcher(s[i+1]);a=m.find()?m.group():null;b=n.find()?n.group():null;if(a!=null&b!=null){s[i]=s[i].replaceFirst(a,b);s[i+1]=s[i+1].replaceFirst(b,a);}}return l.join(" ",s);}

Try it online!

Ungolfed:

String swapVowels(String line) {
    String[] parts = line.split(" ");
    Pattern pattern = Pattern.compile("([aeiouy]+)");
    for (int i = 0; i < parts.length - 1; i += 2) {
        Matcher matcherL = pattern.matcher(parts[i]), matcherR = pattern.matcher(parts[i + 1]);
        String vowelRunL = matcherL.find() ? matcherL.group() : null, vowelRunR = matcherR.find() ? matcherR.group() : null;
        if (vowelRunL != null & vowelRunR != null) {
            parts[i] = parts[i].replaceFirst(vowelRunL, vowelRunR);
            parts[i + 1] = parts[i + 1].replaceFirst(vowelRunR, vowelRunL);
        }
    }
    return String.join(" ", parts);
}

Bashful Beluga

Posted 2017-06-13T20:07:54.113

Reputation: 413

2

You can remove the parenthesis around the input ((l)-> to l->). You can add import java.util.regex.*; to the byte-count, and remove all other java.util.regex.. You can remove the parenthesis in the regex ("([aeiouy]+)" -> "[aeiouy]+"). And you can change String[]s=l.split(" "); to String s[]=l.split(" "),a,b;, then you can remove the String inside the for-loop; And you can change String.join(" ",s); to l.join(" ",s);. Here is it all combined. [329 bytes]

– Kevin Cruijssen – 2017-06-14T06:54:30.750

@KevinCruijssen Indeed! Edited, thank you! :-) – Bashful Beluga – 2017-06-14T12:15:51.527

2

Perl, 58 bytes

57 bytes code + 1 for -p.

$v="([aeiouy]+)";s!\w+ \w+!$&=~s/$v(.* .*?)$v/$3$2$1/r!ge

-2 bytes thanks to @Dada!

Try it online!

Dom Hastings

Posted 2017-06-13T20:07:54.113

Reputation: 16 415

Just a couple of bytes to save by dropping a ? and storing ([aeiouy]+) in a variable: Try it online!

– Dada – 2017-06-22T13:55:20.047

1

Ruby, 87+1 = 88 bytes

Uses the -p flag.

gsub(/(\w+) (\w+)/){_,a,b=*$~;a[r=/[aeiouy]+/]&&b[r]?a.sub(r,b[r])+' '+b.sub(r,a[r]):_}

Try it online!

Value Ink

Posted 2017-06-13T20:07:54.113

Reputation: 10 608

1

Python 3, 198 196 192 bytes

  • Saved 6 bytes: thanks to Zachary T : if(m and n) to if m and n & removed unwanted r for regex string, index i starting from 1 instead of 0
from re import*
s=search
a=input().split()
v="[aeiouy]+"
j=1
while j<len(a):
 i=j-1;m=s(v,a[j]);n=s(v,a[i])
 if m and n:a[i]=sub(v,m[0],a[i],1);a[j]=sub(v,n[0],a[j],1)
 j+=2
print(' '.join(a))

Try it online!

officialaimm

Posted 2017-06-13T20:07:54.113

Reputation: 2 739

1I think you can shave three bytes off your program: one by removing the r before your string, another by changing i+1<len(a) to i<=len(a), and the third by changing if(m and n) to if m and n. – Zacharý – 2017-06-14T15:37:26.727

1Thanks. But the i+1<len(a) cannot be changed to i<=len(a) or else it will try to evaluate a[j] i.e. a[i+1] for i=len(a) and cause index out of range error: – officialaimm – 2017-06-14T15:51:09.423

Sorry, I was reading that as i<len(a)+1, whoops! – Zacharý – 2017-06-14T15:54:36.937

1

Would this work? https://repl.it/IlX1

– Zacharý – 2017-06-14T16:00:39.737

Yes, it works. You saved 2 bytes, Thank you!! – officialaimm – 2017-06-14T16:04:59.167

1You have extraneous spaces at the end of some of your lines, I counted 192 bytes. – Zacharý – 2017-06-18T17:12:41.787

Yep, that and I had not even updated the tio link. Thanks. – officialaimm – 2017-06-18T17:21:00.533

Hey, would this work? https://repl.it/Iql5

– Zacharý – 2017-06-18T17:54:57.813