| Bytes | Lang | Time | Link |
|---|---|---|---|
| 072 | Perl Mutf8 MUnicodeNormalize | 240731T140151Z | 鳴神裁四点一号 |
| 055 | Raku Perl 6 rakudo | 240802T012639Z | bb94 |
| 051 | Haskell + hgl | 240801T025540Z | Wheat Wi |
| 031 | 05AB1E | 240812T085233Z | Kevin Cr |
| 054 | Charcoal | 240801T084735Z | Neil |
| 039 | Retina 0.8.2 | 240731T235023Z | Neil |
| 030 | Jelly | 240731T184150Z | Jonathan |
Perl -Mutf8 -MUnicode::Normalize, 72 bytes
Thanks @bb94!
sub{s/ae/a/ig;$_=NFD$_;s/\pM//ug;($_.z.reverse)=~/[ei][^aeiouz]+[aou]/i}
Perl -Mutf8 -MUnicode::Normalize, 75 bytes
Inverted truthy and falsey.
sub{s/ae/a/ig;$_=NFD$_;s/\pM//ug;s/[^aeiou]+/_/gi;/[aou]_[ei]|[ei]_[aou]/i}
Raku (Perl 6) (rakudo), 56 55 bytes
{s:g:i/ae/a/;$_|.flip!~~m:i:m/[e|i]<-[aeiou]>+<[aou]>/}
Explanation
The string-and-reverse trick was inspired by Wheat Wizard’s Haskell + hgl answer.
{s:g:i/ae/a/;$_|.flip!~~m:i:m/[e|i]<-[aeiou]>+<[aou]>/}
s:g:i/ae/a/; # Replace all instances of `ae` with `a` in the input (case-insensitively)
$_|.flip!~~ # Does neither that string nor its reverse match...
m:i:m/[e|i]<-[aeiou]>+<[aou]>/ # the regex /[ei][^aeiou]+[aou]/ (case- and diacritic-insensitively)?
💎
Created with the help of Luminespire.
Haskell + hgl, 78 60 51 bytes
(ma.*pPX"[ei][^aeiou]+[aou]"~<rv)<rmD<<skX"ae_"<mtL
Explanation
This works by making some reductions on the input and then running a simple regex on both the string and its reverse.
mtLconvert to lower case.skX"ae_"replaceaewitha.rmDremove the síntí fada.~<rvon both the string and reverse ...pPX"[ei][^aeiou]+[aou]"check if the pattern slender-cluster-broad occurs ...maget the logical or.
No regex, 69 bytes
(ma.*pP(ah'$xys"ei"<>so(nxy W5)<>xys"aou")~<rv)<rmD<<sk(ʃa<*ʃe)<mtL
Reflection
- There should be a version of
gkYbut for regexes. - There should be
pPXbut not for regexes. That is combinepPwithah'. - I could probably add a builtin for
"aeiouáéíóú". - This regex reminds me of the regex used here. There might be a way to systematize this a bit to save bytes.
- Just has
xayhas a string version there should be a string version ofnxy. - Just as there are
(<>?)and(?<>), there should be(<>*),(*<>),(<>+)and(+<>). - We could use some more versions of
sY, or "split along". There'ssYeto split along characters from a list of options, but it would be nice to have the opposite, to split along characters absent from a list. It would also be good to have variants for all of these that remove empty strings from the output, i.e. to split along clusters of matching characters.
05AB1E, 31 bytes
l„ae¬:žPS¡õKü2εεN<è"eiéí"så}Ë}P
Try it online or verify all test cases.
Explanation:
l # Convert the (implicit) input-string to lowercase
„ae # Push string "ae"
¬ # Push its first character "a" (without popping)
: # Replace all "ae" with "a" in the lowercase input
žP # Push the consonants constant "bcdfghjklmnpqrstvwxz"
S¡ # Split the string on each consonant
õK # Remove all empty strings (where multiple adjacent consonants were)
ü2 # Pop and push all overlapping pairs
ε # Map over each pair:
ε # Map over both vowel-strings in each pair:
N # Push the 0-based index
< # Decrease it by 1
è # Use it to index into the vowel-string;
# N=0 → -1 → last character; N=1 → 0 → first character
"eiéí"så # Check if this character is one of "eiéí"
}Ë # After the inner map: Check if both vowel-checks are the same;
# [1,1] for both slender; [0,0] for both broad; or
# [0,1] or [1,0] for invalid
}P # After the outer map: Check if all are truthy
# (after which the result is output implicitly)
Charcoal, 54 bytes
¹FEE⪫⪪Sae¦a℅﹪℅↧ι¹³²⁻№]aouvι№eiι«F∧ι∧№υ⁰№υ±ι⎚F↔ι≔⟦⟧υ⊞υι
Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for valid, nothing if not. Explanation:
¹
Assume the word is valid.
FEE⪫⪪Sae¦a℅﹪℅↧ι¹³²⁻№]aouvι№eiι«
Replace ae in the input with a, then for each letter, lowercase it, then reduce its ordinal modulo 132, which converts á to ], ú to v (which fortunately isn't a valid input) and the other accented letters to their base letter, then finally determine whether it's a broad vowel (mapped to 1), a slender vowel (mapped to -1) or a consonant (mapped to 0). Loop over the resulting list of letter types.
F∧ι∧№υ⁰№υ±ι⎚
If this is a vowel, the previous vowel was the other type of vowel, and there was an intervening consonant, then clear the canvas, marking the word as invalid.
F↔ι≔⟦⟧υ
If this is a vowel then clear any saved letter types.
⊞υι
Save the type of this letter.
Retina 0.8.2, 39 bytes
ae|[aáoóuú]
#@
[eéií]
@#
i)1`(#|@)\w+\1
Try it online! Link includes test cases. Outputs an inverted result, i.e. 0 for valid, 1 for invalid. Explanation:
i)`
Run the whole script case-insensitively.
ae|[aáoóuú]
#@
Mark broad vowels with #@.
[eéií]
@#
Mark slender vowels with @#.
1`(#|@)\w+\1
Check for consonants surrounded by vowels of different types (which equates to having surrounding symbols of the same type).
Note that Retina defaults to the ISO-8859-1 code page so all of the Irish vowels only cost one byte.
Jelly, 30 bytes
Œlœṣ⁾aeKe€ØCœpƊO%65%9Ḃj€-FSƝ1e
A monadic Link that accepts a list of the specified characters and yields 0 for valid or 1 for invalid.
How?
Œlœṣ⁾aeKe€ØCœpƊO%65%9Ḃj€-FSƝ1e - Link: list of characters (limited to those specified)
Œl - convert to lowercase (works for fada e.g.: 'Ó' -> 'ó')
⁾ae - "ae"
œṣ - split {Lowercased} at occurrences of {"ae"}
K - join with spaces (we'll treat this as a wide vowel later)
Ɗ - last three links as a monad:
ØC - consonants -> "BCD...Zbcd...z"
€ - for each {C in our string}:
e - {C} exists in {"BCD...Zbcd...z"}?
œp - partition {our string} at truthy indices of {that}
discarding the borders
O - cast to ordinals
%65 - mod 65
%9 - mod 9
Ḃ - mod 2
j€- - join each with -1
F - flatten
Ɲ - for neighbouring pairs:
S - sum
1e - contains 1?