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
academy    -> 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 – LyricLy Sep 9 '17 at 21:49
  • 1
    Is the empty word "" a possible input? – Silvio Mayolo Sep 9 '17 at 23:28
  • @SilvioMayolo It is not. – LyricLy 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. – Truth-seek Sep 10 '17 at 4:42
  • 1
    a "banana" is full of hate – jstnthms Sep 11 '17 at 15:19

28 Answers 28

JavaScript (ES6), 36 28 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 – Matheus Avellar Sep 9 '17 at 22:22
  • 1
    @MatheusAvellar Without the +0, it would return false positives on words ending with a consonant. – Arnauld 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! – Matheus Avellar Sep 9 '17 at 22:26
  • You should be able to omit the ! (two distinct values) – LarsW Sep 10 '17 at 7:59
  • @LarsW Thanks! I didn't notice this rule. – Arnauld 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ẇ

A monadic link taking a list of characters and returning:

  • 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... – Erik the Outgolfer Sep 10 '17 at 8:17
  • what do you mean? – Jonathan Allan Sep 10 '17 at 8:54
  • the hacky thing in your code...otherwise you could've done e€ØY;1w11 or something – Erik the Outgolfer Sep 10 '17 at 9:04
  • Why eleven? String words didn't seem to be tied to the number eleven in any way – hyiltiz 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]. – Jonathan Allan 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. – sundar Aug 10 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?) – sundar Aug 10 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. – Adnan Aug 11 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? – Charlie Sep 13 '17 at 21:12
  • @Charlie I'm not sure how you intend on using $, care to explain that further? – Giuseppe 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) – user5957401 Aug 10 at 20:40

Dyalog APL, 20 bytes

⎕←∧/2∨/0,⍨⍞∊'aeiouy'

Try it online!

  • 3
    I don't think you need ⎕←. – Zacharý 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. – Oberon 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. – Zacharý 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.

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;}. – Jakob Sep 10 '17 at 3:26
  • 1
    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;} – Jakob 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. – Kevin Cruijssen Sep 11 '17 at 12:19
  • 1
    @KevinCruijssen My regex is awful, couldn't get it to work :D. I will pretend that I wanted to be original – Roberto Graham 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. ;) – Kevin Cruijssen Sep 11 '17 at 12:34

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.

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. – Mr. Xcoder Sep 11 '17 at 12:44
  • 1
    @KevinCruijssen Downgoat's userscript tells me it is 13 bytes: 13 ISO-8859-1 bytes, 13 chars. I think that should be fine – Mr. Xcoder Sep 11 '17 at 12:46
  • @KevinCruijssen Should be fixed now. – Mr. Xcoder 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? – Mr. Xcoder Sep 11 '17 at 13:10
  • @KevinCruijssen Lol, it's your browser's font. – Mr. Xcoder Sep 11 '17 at 13:20

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 – L3viathan Sep 9 '17 at 23:02
  • Don't you need to assign the lambda to somthing? i.e. f=lambda s... – OldBunny2800 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). – Jonathan Allan 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). – Jonathan Frech Sep 10 '17 at 3:03
  • @JonathanFrech It can get even better – Mr. Xcoder Sep 10 '17 at 7:15

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" – L3viathan Sep 10 '17 at 0:12
  • @L3viathan Empty strings are falsy and non-empty strings are truthy. This is valid. – LyricLy 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. – Silvio Mayolo Sep 10 '17 at 3:36
  • With newline terminated words, this can be shortened to $_=$/if/[^aeiouy]{2}/. – nwellnhof 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
       2\    For all (overlapping) slices of length 2 (the <link><nilad>\ functionality)
      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Ȧ€ – miles 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! – HyperNeutrino Sep 10 '17 at 1:08
  • @miles Nice, thanks! – HyperNeutrino 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
academy
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 =
{Regex(".*[^aeiouy]([^aeiouy].*|$)").matches(it)}
data class TestData(val input: String, val output: Boolean)

fun main(args: Array<String>) {
    val items = listOf(
            TestData("hate", true),
            TestData("love", true),
            TestData("popularize", true),
            TestData("academy", true),
            TestData("you", true),
            TestData("mouse", true),
            TestData("acorn", false),
            TestData("nut", false),
            TestData("ah", false),
            TestData("strong", false),
            TestData("false", false),
            TestData("parakeet", false)
    )

    items
            .filter { s(it.input) == it.output }
            .forEach { throw AssertionError(it.toString()) }

    println("Test Passed")
}

TryItOnline

Based on @Arnauld's Answer

Retina, 23 18 bytes

$
$
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?

Brachylog, 18 11 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")

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';
}
  • 1
    You can remove the space between return and !. – Zacharý 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. – Stephen Sep 12 '17 at 14:34
  • Yes, good idea! Also it is possible to reduce bytes by assuming that input is always in uppercase. – Matias Villanueva Sep 12 '17 at 14:41
  • Oh, and if the regex is a standard regex engine, can't you do [B-Z]? – Stephen Sep 12 '17 at 14:42
  • @Stephen [B-Z] includes vowels. [^AEIOUY] works, though. – LyricLy 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. – LyricLy 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

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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