| Bytes | Lang | Time | Link |
|---|---|---|---|
| 014 | Japt ! | 250720T132950Z | Shaggy |
| 048 | Janet | 250720T104337Z | Adam |
| 024 | Uiua | 241127T044539Z | ErikDaPa |
| 014 | Retina | 250221T153816Z | mbomb007 |
| 022 | Bash | 241126T075733Z | roblogic |
| 032 | Google Sheets | 241127T143917Z | doubleun |
| 024 | Zsh | 241126T025025Z | roblogic |
| 020 | Perl 5 p | 241127T035434Z | Xcali |
| 018 | sed rn | 241126T231546Z | Jan Blum |
| 046 | Python 3 | 241126T215341Z | xnor |
| 019 | Charcoal | 241126T111133Z | Neil |
| 044 | APL+WIN | 241126T105806Z | Graham |
| 059 | Python 3 | 241126T101629Z | Rhaixer |
| 016 | 05AB1E | 241126T084607Z | Kevin Cr |
| 026 | JavaScript V8 | 241126T014956Z | l4m2 |
| 035 | JavaScript V8 | 241126T013402Z | thejonym |
| 019 | Vyxal | 241126T013210Z | lyxal |
Janet, 48 bytes
|(peg/match~(+"ei"(to"cie")(to(*(!"c")1"ei")))$)
Returns nil for valid inputs and @[] for invalid inputs.
Uiua, 20 24 bytes (thx to Jan Blumschein's correction)
¬±⧻regex"cie|[^c]ei|^ei"
Explanation:
¬±⧻regex"cie|[^c]ei|^ei"
regex"cie|[^c]ei|^ei" => find matches of illegal combos
⧻ => is there a match?
± => signum as a bool value and negate
Retina, 14 bytes
I'm surprised nobody used Retina. It outgolfs all the existing answers!
([^c]|^)ei|cie
Returns 0 for truthy, or a positive number for falsy.
I like that the start of the regex kind of looks like an emote-esque face. I will also note that I came up with this answer and regex prior to viewing existing answers.
If you want to view nice TRUE and FALSE output, use this code in the online interpreter:
C`([^c]|^)ei|cie
0
TRUE
\d+
FALSE
Google Sheets, 32 bytes
=1-regexmatch(1&A1,"cie|[^c]ei")
Uses the same regex as many others. Gets 0 for false and 1 for true. Remove the 1- bit to get true for false and false for true and save two bytes.

Zsh, 26 24 bytes
-2 bytes, thanks to @GammaFunction
${1:/(*cie|(|*[^c])ei)*}
Returns 127 for truthy (input obeys the rule), 0 for falsey.
sed -rn, 20 18 bytes
/^ei|[^c]ei|cie/q1
Takes one string on stdin, and returns exit code 0 (1) for strings that do (do not) follow the rule.
Python 3, 46 bytes
lambda s:(q:=s.count)("cie")+q("ei")<=q("cei")
Checks that the count of cie's is zero, and that the the count of ei's equal that of cei's. These are combined into one inequality as cie's + ei's <= cei's. If we may output true/false flipped, we can negate the >= to < to save 1.
50 bytes
lambda s:not re.search("cie|(?<!c)ei",s)
import re
A regex solution. The outer not converts match objects to False, and Nones indicating no match to False. If we could do truthy/falsy reversed, we could use re.compile for 43 bytes:
import re
re.compile("cie|(?<!c)ei").search
Charcoal, 19 bytes
¬∨№θcie⁻⌕Aθei⁺¹⌕Aθc
Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for ie and cei only, nothing if ei or cie. Explanation:
№ Count of
cie Literal string `cie`
θ In input string
∨ Logical Or
⌕A Find All
ei Literal string `ei`
θ In input string
⁻ Set difference
⌕A Find All
c Literal string `c`
θ In input sring
⁺ Vectorised Plus
¹ Literal integer `1`
¬ Logical Not
Implicitly print
Note that using the newer version of Charcoal on ATO I could have saved a byte by using Incremented() instead of Plus(1, ).
APL+WIN, 44 bytes
Prompts for string. Outputs 1=true, 0=false
3=+/2 4 5≠(4⍴2)⊥+/¨ 'cei' 'cie' 'ei' 'ie'⍷¨⊂⎕
Python 3, 59 bytes
Just another boring Python solution with re. None is falsy, an re.Match object is truthy. Basically, the regex confirms the string has no cies, and then any eis without a c behind. It matches the string if both conditions succeeded.
lambda n:re.match("^(?!.*cie)(?!.*(?<!c)ei).*",n)
import re
If you're confused about the True output, expand the header and footer in case it doesn't show. The footer contains some testing code to assert that the function does indeed work according to the test cases.
05AB1E, 20 16 bytes
¬ìAε„eiN<iR}«}åà
Outputs an inverted boolean (0 for truthy; 1 for falsey).
Try it online or verify all test cases.
Explanation:
¬ # Get the first character of the (implicit) input-string
ì # Prepend this letter to the input-string
A # Push the alphabet
ε # Map over each letter:
„ei # Push string "ei"
N<i # If the 0-based index is 2:
R # Reverse it to "ie"
}« # After the if-statement, append it to the letter
}å # After the map: check for each whether it's a substring in the input
à # Pop and check if any is truthy
# (after which the result is output implicitly)
The “ is for edge-cases that start with ei (or test case "ei" itself).
JavaScript (V8), 26 bytes
x=>!/cie|[^c]ei/.test(0+x)
JavaScript (V8), 35 bytes
x=>/^((?!(?<!c)ei|cie).)*$/.test(x)
Admittedly identical to the regex solution ATaco found in chat but we came to our conclusions independently. And mine is in funny javascript.
x=>/^((?!(?<!c)ei|cie).)*$/.test(x) //full program
x=>/ /.test(x) //js regex boilerplate
^ $ //within the entire string
( .)* //for every character,
//(if there are any)
(?! ) //so long as the next few
//characters are not
| //either
cie //"cie"
ei //or an "ei"
(?<!c) //that isnt after "c"
//return true, qed
Vyxal, 152 bitsv2, 19 bytes
`cie`c¬?`.?ei`Ẏ`cei`=A∧
Bitstring:
01101101101000001011111100110011000001010100101101100011101000011110111001011111100111000011101110101010000001000101100101110100001001011010101010010011
The footer converts the 0/1 to FALSE/TRUE respectively for the test cases.
Returns true if cie isn't present and all instances of ei are preceded by a c.
Explained
`cie`c¬?`.?ei`Ẏ`cei`=A∧
`cie`c¬ # Is "cie" absent in the input
∧ # And
A # Are all
`.?ei`Ẏ # Instances of `ei` with the (optional) letter that comes beforehand
`cei`= # Equal to cei?
💎
Created with the help of Luminespire.