Is it a strong word?

They say that hate is a strong word. I wanted to find out why, so I had a good look at the word.

I noticed that every consonant had a vowel after it. That made it look quite strong to me, so I decided that that's what makes a word strong.

I want to find more strong words, so I'll need a program for it!

Finding strong words

Strong words are words where every consonant (letters in the set BCDFGHJKLMNPQRSTVWXZ) is followed by a vowel (letters in the set AEIOUY). That's it. Nothing else matters.

If the word starts with a vowel, you don't have to worry about any of the letters before the first consonant. If the word has no consonants in it at all, it's automatically a strong word!

Some examples of strong words are agate, hate and you. agate is still a strong word because although it starts with a vowel, every consonant is still followed by a vowel. you is a strong word because it has no consonants.

There is no restriction on length for strong words.

The challenge

Write a program or function that takes a non-empty string as input, and outputs a truthy value if it is a strong word or a falsy value if it is not.

Clarifications

• You may decide to take the input in either lowercase or uppercase. Specify which in your answer.
• Words will not contain punctuation of any kind. They will only contain plain letters in the set ABCDEFGHIJKLMNOPQRSTUVWXYZ.
• Instead of truthy and falsy values, you may choose two distinct and consistent values to return for true and false. If you do this, specify the values you have picked in your answer.
• You may alternatively output a falsy value for a strong word and a truthy one for a non-strong word.

Test cases

Input      -> Output
hate       -> true
love       -> true
popularize -> true
you        -> true
mouse      -> true
acorn      -> false
nut        -> false
ah         -> false
strong     -> false
false      -> false
parakeet   -> false


Scoring

Since this is , the answer with the least bytes wins!

• Sandbox Sep 9 '17 at 21:49
• Is the empty word "" a possible input? Sep 9 '17 at 23:28
• @SilvioMayolo It is not. Sep 10 '17 at 0:02
• @LyricLy If input is "academy" then output should be false, the way I understand the problem. Because 'm' is a consonant. Sep 10 '17 at 4:42
• a "banana" is full of hate Sep 11 '17 at 15:19

JavaScript (ES6), 3628 27 bytes

Saved 1 byte by inverting the result, as suggested by LarsW

Takes input in lowercase. Returns false for a strong word and true for a non-strong word.

s=>/[^aeiouy]{2}/.test(s+0)


How?

We append a 0 (non-vowel) at the end of the input string and look for two consecutive non-vowel characters. This allows us to cover both cases that make a word not strong:

• it contains two consecutive consonants
• or it ends with a consonant

Test cases

let f =

s=>/[^aeiouy]{2}/.test(s+0)

;[
"hate", "love", "popularize", "academy", "you", "mouse", "a", "euouae",
"acorn", "nut", "ah", "strong", "false", "parakeet"
]
.forEach(s => console.log(s + ' --> ' + f(s)))

• Why +0, though? It seems to work fine without it Sep 9 '17 at 22:22
• @MatheusAvellar Without the +0, it would return false positives on words ending with a consonant. Sep 9 '17 at 22:23
• I see, without that it can't find 2 consecutive non-vowels if it's the last letter of the word. Smart! Sep 9 '17 at 22:26
• You should be able to omit the ! (two distinct values) Sep 10 '17 at 7:59
• @LarsW Thanks! I didn't notice this rule. Sep 10 '17 at 8:27

Python 2, 48 bytes

lambda s:'se, F'in[v in'aeiouy'for v in s+'b']


An unnamed function taking a (lowercase) string, s, and returning False if strong or True if not.

Try it online! (inverts the results to match the OP)

How?

Non-strong words have either a consonant followed by a consonant or end in a consonant.

The code adds a consonant to the end (s+'b') to make the required test be just for two consonants in a row.

It finds out if each letter in the altered word is a vowel with the list comprehension [v in'aeiouy'for v in s+'b'].

It now needs to check for two False results in a row (signalling a non-strong word), it does so by getting a string representation (using ...) of this list and looking for the existence of 'se, F'. This is the shortest string found in 'False, False' but none of: 'True, True'; 'False, True'; or 'True, False'.

As an example consider 'nut', the list comprehension evaluates each letter, v, of 'nutb' for existence in 'aeiouy' yielding the list [False, True, False, False], the string representation of this list is '[False, True, False, False]' which contains 'e, F' here: '[False, True, Fals>>e, F<<alse]' hence the function returns True meaning that nut is not a strong word.

Jelly,  10  9 bytes

e€ØY;Ạ11ẇ


• 0 if strong
• 1 if not

Try it online! or see the test-suite.

How?

e€ØY;Ạ11ẇ - Link: list of characters, s      e.g. "hate"  or  "you"  or  "not"
ØY      - consonant yield                   "BCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz"
e€        - exists in? for €ach letter            [1,0,1,0]   [0,0,0]    [1,0,1]
Ạ    - all truthy? (1 for any valid input)   1           1          1
;     - concatenate                           [1,0,1,0,1] [0,0,0,1]  [1,0,1,1]
11  - literal eleven
ẇ - sublist exists?                       0           0          1
-  N.B.: left of ẇ implicitly makes digits so it looks for the sublist [1,1]


Note: The reason for using Ạ is just to save a byte over using 1 (since we then want to use 11 straight away).

• hmm, consistent values... Sep 10 '17 at 8:17
• what do you mean? Sep 10 '17 at 8:54
• the hacky Ạ thing in your code...otherwise you could've done e€ØY;1w11 or something Sep 10 '17 at 9:04
• Why eleven? String words didn't seem to be tied to the number eleven in any way Sep 12 '17 at 0:26
• @hyiltiz when the dyad ẇ has a left argument that is a number it gets implicitly converted to a decimal list of digits, so the eleven becomes [1,1]. Sep 12 '17 at 0:46

05AB1E, 8 bytes

Code

žPS¡¦õÊP


Uses the 05AB1E encoding. Try it online!

Explanation

žPS¡         # Split the string on consonants (bcdfghjklmnpqrstvwxz)
¦        # Remove the first element of the array to handle cases when the
string starts with a consonant
õÊP     # Check if the empty string is not in the array


Example

             # "popularize"
žPS¡         # ['', 'o', 'u', 'a', 'i', 'e']
¦        # ['o', 'u', 'a', 'i', 'e']
õÊ      # [1, 1, 1, 1, 1]
P     # 1

• Maybe I'm missing something, but this seems to always return 1? It returns 1 for both the truthy cases I tried and the falsey testcases. Aug 10 '18 at 18:51
• (Oh, I just noticed how old this answer (and question) is. I guess something in the language has changed in the meantime?) Aug 10 '18 at 19:43
• @sundar Yes nice catch! It seems that I broke the split function at some point. I will fix this as soon as possible. Aug 11 '18 at 12:22

R, 43 bytes

function(s)grep("[^aeiouy]{2}",paste(s,""))


Try it online!

A port of Arnauld's JavaScript answer; returns 1 for weak words and integer(0) for strong ones; it appends a (space) to the end of the string.

This is actually vectorized; with a vector of strings, it returns the indices (1-based) of the weak words.

• Same comment here, can't you use $in the regex instead of adding a space? Sep 13 '17 at 21:12 • @Charlie I'm not sure how you intend on using $, care to explain that further? Sep 13 '17 at 21:33
• Like this solution a lot. I think the logic is clearer (and bytes the same) with paste0(s,0), but that is just quibbling. I think @Charlie is referencing something like this: grep("[^aeiouy]([^aeiouy]|$)",s) Aug 10 '18 at 20:40 Dyalog APL, 20 bytes ⎕←∧/2∨/0,⍨⍞∊'aeiouy'  Try it online! • I don't think you need ⎕←. Sep 10 '17 at 16:08 • @Zacharý I used not to put it, but I was later told (by Dennis, I believe) that a program should not assume to be run in a REPL. Sep 13 '17 at 15:00 • What language did he tell you that about? Was it for Dyalog APL? I know that policy definitely applies for Python/JavaScript/etc. Sep 13 '17 at 20:44 Haskell, 61 54 bytes f=and.(zipWith(||)=<<tail).(map(elem"aeiouy")).(++"z")  Try it online! I had to add a z at the end of the string to handle the case of a trailing consonant. Husk, 12 bytes ΛΣX_2m€¨γaıu  Try it online! Thanks to H.PWiz for help with -4. Returns inconsistent but appropriately truthy or falsy values. Thanks to Leo for -1, now returns consistent truthy/falsy value. • Shorter compressed string. String compression is still way too slow, I need to work on it some more – Leo Sep 12 '17 at 0:52 • @Leo I think that's an NP problem unfortunately. Sep 12 '17 at 9:45 Java (OpenJDK 8), 93 81 bytes s->{int w=0,p=w,l;for(char c:s)w|=p&(p=l="aeiouy".indexOf(c)>>31);return w+p>=0;}  Try it online! • I'm afraid booleans are not the answer: s->{int w=0,p=w,l;for(char c:s){l="aeiouy".indexOf(c)>>31;w|=p&l;p=l;}return w+p>=0;}. Sep 10 '17 at 3:26 • Or you can even do this: s->{int w=0,p=w,l;for(char c:s)w|=p&(p=l="aeiouy".indexOf(c)>>31);return w+p>=0;} Sep 10 '17 at 3:34 • Nice answer, but with this challenge a simple regex-matching is actually quite a bit shorter. Still, +1 from me. Sep 11 '17 at 12:19 • @KevinCruijssen My regex is awful, couldn't get it to work :D. I will pretend that I wanted to be original Sep 11 '17 at 12:21 • @RobertoGraham "I will pretend that I wanted to be original" Well, it certainly is. :) And I used to be pretty bad at regex as well, but after quite a few other answers here on PPCG using regex I'm getting more used to it. And I had already figured out how to match consonants using [a-z&&[^aeiouy]] in a previous answer of mine. ;) Sep 11 '17 at 12:34 Pyth, 18 bytes :+Q1."2}M>åYà  Verify all the test cases. "Borrowed" the regex from the JS answer. This returns False for strong words, True otherwise • @KevinCruijssen In fact, Pyth uses ISO-8859-1. That's why I am not convinced. Sep 11 '17 at 12:44 • @KevinCruijssen Downgoat's userscript tells me it is 13 bytes: 13 ISO-8859-1 bytes, 13 chars. I think that should be fine Sep 11 '17 at 12:46 • @KevinCruijssen Should be fixed now. Sep 11 '17 at 12:56 • @KevinCruijssen I don't see any difference. What is code do you see in my answer and what code do you see in my testing link? Sep 11 '17 at 13:10 • @KevinCruijssen Lol, it's your browser's font. Sep 11 '17 at 13:20 Brachylog, 1811 10 bytes ,Ḷs₂{¬∈Ẉ}ᵐ  Try it online! Neat and simple (except maybe for the 2 extra initial bytes to handle the final consonant case, like "parakeet"). Is falsey for strong words and truthy for non-strong words. ,Ḷ % append a newline (non-vowel) at the end of input, % to catch final consonants s₂ % the result has some substring of length 2 {¬∈Ẉ}ᵐ % where neither of its elements belong to % the set of alternate vowels (with "y")  Perl 5, 31 bytes (30 + 1) $_=''if/[^aeiouy](?![aeiouy])/


+1 byte for -p command line flag. Prints the word if it's a strong word, or the empty string if it is not.

• "two distinct and consistent values" Sep 10 '17 at 0:12
• @L3viathan Empty strings are falsy and non-empty strings are truthy. This is valid. Sep 10 '17 at 0:26
• @L3viathan Perl's truthiness rules are actually very conducive to challenges like this. It's not the first time I've exploited that exact fact. Sep 10 '17 at 3:36
• With newline terminated words, this can be shortened to $_=$/if/[^aeiouy]{2}/. Sep 11 '17 at 13:14

Jelly, 11 bytes

e€ØY;1a2\¬Ȧ


Try it online!

e€ØY;1a2\¬Ȧ  Main link
€           For each letter
e            Is it an element of
ØY         The consonants (excluding Yy)?
;1       Append 1 (true) (consonant) to make sure last letter isn't consonant
a      Logical AND of the two values; is it a consonant pair?
¬   Logical NOT vectorizing; for each (overlapping) pair, is it not a consonant pair?
Ȧ  Any and all; make sure all pairs are not consonant pairs


Yes I know I've been beaten a lot by Jonathan Allan but I wanted to share my approach anyway :P

-4 bytes by stealing a little bit of Jonathan Allan's answer (instead of appending a consonant to check for last-letter edge case, just append 1)
-1 byte thanks to miles

• You can save a byte using either a2\ or Ȧ2Ƥ instead of ṡ2Ȧ€ Sep 9 '17 at 23:07
• @JonathanAllan facepalm I deliberately made sure to use ØC to make sure Yy was counted as a consonant because somehow I remembered backwards. Thanks! Sep 10 '17 at 1:08

Awk, 39 bytes

/([^aeiouy]{2}|[^aeiouy]$)/{print "n"}  prints n for non-strongword, nothing (or, just a newline) for strongword following the pack and searching for two consecutive non-vowels on lowercase input testing $ awk -f strongwork.awk
hate
love
popularize
you
mouse
acorn
n
nut
n
ah
n
strong
n
false
n
parakeet
n


Kotlin, 49 bytes

{Regex(".*[^aeiouy]([^aeiouy].*|$)").matches(it)}  True and false are swapped Beautified { Regex(".*[^aeiouy]([^aeiouy].*|$)").matches(it)
}


Test

var s:(String)->Boolean =
$1[^aeiouy]{2}  Try it online! Outputs 0 for strong, 1 if not. Add 1 byte to support mixed case. Edit: Saved 5 bytes thanks to @ovs. • 18 bytes by appending a consonant to the end. – ovs Sep 10 '17 at 11:52 Java 8, 53 42 bytes s->s.matches(".*[^aeiouy]([^aeiouy].*|$)")


-11 bytes by using the same regex as in @jrtapsell's Kotlin answer instead.

Try it here. (false if strong; true if not)

Explanation:

s->               // Method with String parameter and boolean return-type
s.matches(      //  Checks if the String matches the following regex:
".*           //   One or more characters
[^aeiouy]    //   Followed by a consonant
([^aeiouy].* //   Followed by another consonant (+ any more characters)
|$)") // Or the end of the String // End of method (implicit / single-line return statement)  So it basically checks if we can find two adjacent consonants, or if the String ends with a consonant. Old answer (53 bytes): s->s.matches("[aeiouy]*([a-z&&[^aeiouy]][aeiouy]+)*")  Try it here. (true if strong; false if not) Uses regex to see if the input-String matches the 'strong'-regex. Note that String#matches in Java automatically adds ^...$ to check if the String entirely matches the given regex.

Explanation":

 s->                   // Method with String parameter and boolean return-type
s.matches(           //  Checks if the String matches the following regex:
"[aeiouy]*         //   0 or more vowels
([a-z&&[^aeiouy]]  //     { A consonant,
[aeiouy]+)        //       plus one or more vowels }
*")                //    Repeated 0 or more times
// End of method (implicit / single-line return statement)


A search instead of matches (like a lot of other answers use) is actually longer in Java:
70 bytes:

s->java.util.regex.Pattern.compile("[^aeiouy]{2}").matcher(s+0).find()


Try it here. (false if strong; true if not)

Ruby, 25 bytes

->w{w+?t!~/[^aeiouy]{2}/}


Try it online!

Everybody else is doing it, so why can't Ruby?

Python 2, 58 bytes

-30 bytes by realizing it can be as simple as Arnauld's JS answer.

lambda s:re.search('[^aeiouy]([^aeiouy]|$)',s)<1 import re  Try it online! • Save 6 bytes by really doing the same as Arnauld Sep 9 '17 at 23:02 • Don't you need to assign the lambda to somthing? i.e. f=lambda s... Sep 9 '17 at 23:41 • @OldBunny2800 not unless you are using the reference within your code (it is acceptable to create an unnamed function one could access for reuse with header or footer code - here with f=\ in a header). Sep 9 '17 at 23:50 • I think you might be able to replace your pattern string '[^aeiouy]([^aeiouy]|$)' (24 bytes) with "[^aeiouy]("*2+")|$)" (21 bytes) to save 3 bytes, as the empty group, (), does not change the search behavior (TIO). Sep 10 '17 at 3:03 • @JonathanFrech It can get even better Sep 10 '17 at 7:15 SOGL V0.12, 19 18 bytes æ"[^ŗy]”ŗ(ŗ|$)”øβ=


Try it Here!

Explanation:

æ                   push "aeiou"
"[^ŗy]”            push "[^ŗy]" with ŗ replaced with pop
ŗ(ŗ|$)” push ŗ(ŗ|$) with ŗ replaced with pop
øβ   replace in the input that regex with nothing
=  check for equality with the original input


05AB1E, 11 bytes

žP¹SåJ1«11å


Try it online!

Uses Jonathan's algorithm, returns 0 for true and 1 for false.

Swift 3.1, 85 bytes

import Foundation
{($0+"0").range(of:"[^aeiouy]{2}",options:.regularExpression)==nil}  Try it here! This borrows Arnauld's regex. Lua, 41 bytes return#(io.read()..0):match"[^aeiouy]+"<2  Reads from standard input Lua (loadstring'ed), 37 bytes return#((...)..0):match"[^aeiouy]+"<2  Reads from function parameter(s) Input is lowercase Sees if there is a string of length 2 or more, consisting only of not vowels (consonants) or if the string ends with a non-vowel Returns true/false C++, 195 194 bytes -1 bytes thanks to Zacharý Uppercase, return true if input is a strong word, false otherwise ( C++ have simple int to bool implicit cast rules, 0 => false, true otherwise ) #include<string> #define C(p)(v.find(e[p])==size_t(-1)) std::string v="AEIOUY";int s(std::string e){for(int i=0;i<e.size()-1;++i)if(e[i]>64&&e[i]<91&&C(i)&&C(i+1))return 0;return!C(e.size()-1);}  Code to test : auto t = { "HATE", "LOVE", "POPULARIZE", "ACADEMY", "YOU", "MOUSE", "ACORN", "NUT", "AH", "STRONG", "FALSE", "PARAKEET" }; for (auto&a : t) { std::cout << (s(a) ? "true" : "false") << '\n'; }  • You can remove the space between return and !. Sep 10 '17 at 15:53 C, 107 Bytes i,v,w,r,t;a(char*s){w=0;for(r=1;*s;s++){v=1;for(i=6;v&&i;)v=*s^" aeiouy"[i--];r=w&&v?0:r;w=v;}return r&~v;}  Returns 1 for strong word and 0 for weak word. Tested with the words given in the main post. C (gcc), 59 bytes f(char*s){return*s?strcspn(s,"aeiouy")+!s[1]<2?f(s+1):0:1;}  Try it online! PHP, 69 bytes preg_match("/([^AEIOUY][^AEIOUY]+|[^AEIOUY]$)/",\$_SERVER['argv'][1]);


Returns 1 is the word is not strong.

• Welcome to PPCG! I believe you can remove spaces to cut some bytes, specifically /", str -> /",str and [1]))) return -> [1])))return but I don't know PHP too well so I can't be sure. Sep 12 '17 at 14:34
• Yes, good idea! Also it is possible to reduce bytes by assuming that input is always in uppercase. Sep 12 '17 at 14:41
• Oh, and if the regex is a standard regex engine, can't you do [B-Z]? Sep 12 '17 at 14:42
• @Stephen [B-Z] includes vowels. [^AEIOUY] works, though. Sep 12 '17 at 20:18
• I don't know PHP either, but you could probably save more bytes by returning the result from the regex match directly, instead of wrapping it in an if statement. Sep 12 '17 at 20:20

CJam, 57 bytes

q{"aeiouy"#W=}%_,:B{_A={_A_)\B(<{=!X&:X;}{0:X;;;}?}&}fA;X
`

Try it online!

Reads input, converts to 1s for consonants, 0s for vowels. For every consonant, AND predefined variable X (predefined to 1) with next character's value. Output X