18
\$\begingroup\$

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"
\$\endgroup\$
  • 1
    \$\begingroup\$ For those who can see deleted posts, the sandbox post was here. \$\endgroup\$ – Comrade SparklePony Jun 13 '17 at 20:09
  • 1
    \$\begingroup\$ If 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? \$\endgroup\$ – DJMcMayhem Jun 13 '17 at 20:18
  • \$\begingroup\$ @DJMcMayhem Vowels can only swap between runs of two words. I will edit. \$\endgroup\$ – Comrade SparklePony Jun 13 '17 at 20:21
  • \$\begingroup\$ 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. \$\endgroup\$ – Bashful Beluga Jun 13 '17 at 22:49
  • \$\begingroup\$ @BashfulBeluga Yep, my mistake. I will fix. \$\endgroup\$ – Comrade SparklePony Jun 13 '17 at 23:00

11 Answers 11

9
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ Your regex doesn't require the end of a word between your two vowel groups. Try it online! \$\endgroup\$ – nmjcman101 Jun 14 '17 at 13:50
  • \$\begingroup\$ @nmjcman101 Are you looking at my old revision? Because that's exactly what I have right now \$\endgroup\$ – DJMcMayhem Jun 14 '17 at 13:52
  • \$\begingroup\$ My TIO link wasn't fixing anything, I just changed the input. It swaps the letters oddly. \$\endgroup\$ – nmjcman101 Jun 14 '17 at 13:53
  • \$\begingroup\$ @nmjcman101 Ah, I see. Fixed now! \$\endgroup\$ – DJMcMayhem Jun 14 '17 at 13:57
6
\$\begingroup\$

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
\$\endgroup\$
5
\$\begingroup\$

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

\$\endgroup\$
4
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

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.
\$\endgroup\$
  • \$\begingroup\$ I tried removing the double [aeiouy]+ but couldn't get something economic. \$\endgroup\$ – Kobi Jun 14 '17 at 6:36
  • 1
    \$\begingroup\$ It's marginally shorter to swap the runs with a sort stage: tio.run/… \$\endgroup\$ – Martin Ender Jun 14 '17 at 7:58
  • \$\begingroup\$ @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: tio.run/… \$\endgroup\$ – Kobi Jun 14 '17 at 8:24
3
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

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)
\$\endgroup\$
2
\$\begingroup\$

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);
}
\$\endgroup\$
  • 2
    \$\begingroup\$ 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] \$\endgroup\$ – Kevin Cruijssen Jun 14 '17 at 6:54
  • \$\begingroup\$ @KevinCruijssen Indeed! Edited, thank you! :-) \$\endgroup\$ – Bashful Beluga Jun 14 '17 at 12:15
2
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ Just a couple of bytes to save by dropping a ? and storing ([aeiouy]+) in a variable: Try it online! \$\endgroup\$ – Dada Jun 22 '17 at 13:55
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
  • 1
    \$\begingroup\$ I 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. \$\endgroup\$ – Zacharý Jun 14 '17 at 15:37
  • 1
    \$\begingroup\$ Thanks. 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: \$\endgroup\$ – officialaimm Jun 14 '17 at 15:51
  • \$\begingroup\$ Sorry, I was reading that as i<len(a)+1, whoops! \$\endgroup\$ – Zacharý Jun 14 '17 at 15:54
  • 1
    \$\begingroup\$ Would this work? repl.it/IlX1 \$\endgroup\$ – Zacharý Jun 14 '17 at 16:00
  • 1
    \$\begingroup\$ You have extraneous spaces at the end of some of your lines, I counted 192 bytes. \$\endgroup\$ – Zacharý Jun 18 '17 at 17:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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