# Count /[^a-z]/ig with /[a-z]/ig

Write a program or function which takes a string of text as input and outputs the number of non-alphabetical characters in it (standard I/O rules apply). A non-alphabetical character is any character not appearing in this string:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ


In terms of ASCII character codes, that's anything not in ranges 65-90 inclusive or 97-122 inclusive.

## Rules

Your program must be able to handle all of printable ASCII, as well as any characters that appear in your code. In other words, you may assume input will not contain any characters iff they are in neither printable ASCII nor your solution. Printable ASCII here means ASCII's character codes 32-126 inclusive as well as character code 10 (Meaning you will have to count spaces and newlines).

You may assume that input will not be empty.

## Scoring

Your score is the number of non-alphabetical characters (not bytes!) in your code. Lowest score wins, with as a tie-breaker.

## Examples

"input" => output
"example" => 0
"3xampl3" => 2
"Hello, World!" => 3
"abc.def-" => 2
"     " => 5
"IT'S NORMAL" => 2
"•¥¥€???!!!" => 10
"abc
def" => 1

• I suggest renaming this to what the challenge actually is. At first I though this was some kind of complex number challenge. Jun 8 at 18:48
• @Seggan I could switch the order of the regex flags :P but yea it's pretty vanilla regex, I dunno. I'll think about verbosifying it. Jun 8 at 19:23

# Vyxal, score 0, 4 bytes

kLFL


Yes, you heard me right. Flagless, score 0, 4 bytes.

## Explanation

kLFL
kL    Uppercase and Lowercase alphabet
F   Filter out the input
L  Take the length of that


# Husk, Score 0, 13 11 bytes*

mLfopVDkDma


Try it online!

The basic idea is to filter for non-alphabetic characters and calculate the length. Husk has a builtin (D) to identify uppercase characters, and we can convert the lowercase characters to uppercase first using a. But now we need to filter to keep only falsy elements. This isn't very straightforward in Husk: the builtin 'NOT' command is the (non-alphabetic) ¬ character, so we need to engineer an alternative to this.

This is accomplished here by first grouping elements into lists, and getting the index of the first truthy element of each list (so, lists of truthy elements return 1 and lists of falsy elements return 0 for 'not found'). After this, getting prime factors (p command) was the trick: this returns a non-empty list (=truthy) containg a single 0 element for 0, and an empty list (=falsy) for 1.
And a few other little tricks to get the length of the resulting single-element list.

Altogether:

FYmLfopVDkDma
m   # Map across each character in the input:
a  #   convert to uppercase;
k     # now, group the characters by:
D    #   are they an uppercase letter?
#   (zero for non-uppercase letters, ASCII value for uppercase letters);
f          # now filter this list by:
o         #   the combination of these two commands:
VD      #      first index of an uppercase letter (or zero if not found)
p        #      prime factors of this (so non-empty list for groups of non-letters, empty otherwise)
# Now we've got a single-element containing all the
# non-alphabetic characters of the input, or an empty list if there aren't any.
# We need to get the length of this single element (or zero if there isn't one).
m            # So: map across this list (it only has one element)
L           #   getting the element length(s)

# Output formatting:

F              # Fold across this (single-element) list of lengths,
Y             #   getting the maximum value (so the value of the only element)


*outputs an empty list for zero non-alphabetic characters, and a single-element list containing the number of non-alphabetic characters otherwise. Add 2 bytes (FY) to output the number of non-alphabetic characters in a non-listed fashion Try it online!

• is FY necessary? Feels like something standard i/o would be lenient on IMO Jun 8 at 15:48
• @thejonymyster - without the FY the output would be either a single-element list containing the number of non-alphabetic characters, or an empty list if there are none (as in the first test-case). It seemed neatest to me to convert this into a direct number (and in so doing convert the empty list to zero)... but it's your challenge: if you think it's Ok to drop the FY I'll happily do so! Jun 8 at 15:57
• I try to defer to the defaults as much as possible :P I think it's fine to drop it. If it were something like "returns the number, unless its 0, in which case it returns the letter e", that'd be fishy, but there's nothing ambiguous about [] being 0, so it shouldn't be controversial imo. Jun 8 at 16:01
• @thejonymyster - Ok, thanks, updated (and pleasingly ties with Pyth now, although Pyth has a more-conventional output format...). Jun 8 at 19:31
• It is an eternal struggle between "this looks good" vs. "this is golfier"... orz Jun 8 at 19:37

# Charcoal -v, 36 bytes, score 0

CastLengthFilterqNotCountaUppercasei


Try it online! Explanation: Charcoal's verbose parser is somewhat lax, not always requiring things like parentheses, spaces, commas, or correct capitalisation. The verbose program would be more conventionally written something like this:

Print(Cast(Length(Filter(q, Not(Count(a, Uppercase(i)))))));


q is the first input, a is the predefined variable for the uppercase alphabet and i is the default outer loop variable.

• This is wild. How is it even possible for this not to cause intractable problems lol. Jun 9 at 0:03
• @chunes Well, I got lucky that the parser recognises variable names if the next letter is in upper case.
– Neil
Jun 9 at 0:09

# Pip, score 0, 8 bytes

oMSaRMXA


Try It Online!

-3 thanks to DLosc.

    RM   # Remove...
XA # Letters
a     # From input
MS      # Sum result when mapping each to...
o        # 1

• This is a [code-challenge], you should probably include your score (0) as well as your byte count Jun 9 at 15:43

# 05AB1E, score: 0 (7 bytes)

ADuJSKg


Try it online or verify all test cases. (The Join in the test suite has been replaced with a concat «, because it would otherwise join the input that's already on the stack with it.)

The straight-forward shortest approach would be 3 bytes with a score of 2:

áмg


Explanation:

A       # Push the lowercase alphabet
D      # Duplicate it
u     # Uppercase the copy
J    # Join the two alphabet on the stack together
S   # Convert it to a list of characters
K  # Remove all those characters from the (implicit) input-string
g # Pop and push the length to get the amount of remaining non-letters
# (which is output implicitly as result)

á       # Only leave all letters of the (implicit) input-string
м      # Remove all those letters from the (implicit) input-string
g     # Pop and push the length to get the amount of remaining non-letters
# (which is output implicitly as result)


# Pyth, Score 0, 14 11 bytes

lfqZhxGrTZQ


Try it online!

G is the lowercase alphabet in Pyth. There's no built-in for the uppercase alphabet, so we convert each letter of the input to lowercase.

Explanation

f ... Q Filter for elements of the input where...

xGrTZ ...the index of the lowercased letter in the lowercase alphabet ...

h ...plus one...

qZ ... equals 0

(This works because x returns -1 for elements not in the string, like in Python)

l Length of the resulting list

• I'm not familiar with the syntax, but do you think you could golf the qZh by instead checking if the index is less than 0? rather than checking if it's specifically -1 Jun 8 at 16:11
• @thejonymyster Yup, 10 bytes: lf>ZxGrTZQ. But the byte count didn't matter, I thought? Also, that means a score of 1. Jun 8 at 16:21
• @Steffan Oh, lol I forgot > wasn't a letter or something. Byte count matters for tie breakers but you're right, score 1 is worse than score 0 no matter the bytecount :P Thanks for verifying though Jun 8 at 16:37

# R, score 9, 38 bytes

function(x)sum(!tolower(x)%in%letters)


Try it online!

Takes input as a vector of characters.

# R, score 14, 85 bytes

function(x)nchar(gsub("[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]","",x))


Try it online!

Takes input as a proper string.

# Burlesque, Score 0, 9 bytes

qrdfnsait


Try it online!

qrd  # Quoted isalpha
fn   # Filter not
sa   # Non-destructive length (ordinary length is L[)
it   # Drop everything but the top of stack


Absolute shortest doing the same thing would be:

FrdL[

F   # Filter not
rd   # isalpha
L[   # Length


For fun, the inverse challenge:

^^ ^^ ^^ ^^ ^^           # Create 5 copies
).%++\/                  # Count isPunctuation; add; swap
).*++.+\/                # Count isSymbol; add; swap
)<>++.+\/                # Count isDigit; add; swap
" "~?)-])**++32./.+\/    # Count spaces; add; swap (is whitespace is "ra")
"   "~?)-])**++9./.+\/   # Count tabs; add; swap
"
"~?)-])**++10./.+        # Count newlines; add; swap


Try it online!

# Java, score: 14 (46 bytes)

s->s.filter(c->!Character.isLetter(c)).count()


Input as a Character-stream.

Doesn't work if the input contains non-ASCII letters (e.g. é), but that's allowed according to the challenge rules.

Try it online.

Explanation:

s->                          // Method with IntStream parameter & long return
s.filter(c->               //  Filter the character of the input-stream by:
!Character.isLetter(c)) //   It's NOT a letter
.count()                  //  Count how many are left


# Haskell, score 6, 81 bytes

length.filter(flip notElem"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")


Try it online!

The non-alphabetic characters are .( "").

Also score 6, but 4 bytes longer is:

fmap length$filter$flip notElem"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"


Try it online!

# JavaScript (in Browser), Score 4, 120 bytes

eval(atobZXZhbCgicyAgPSIrICAiPnMubWEiKyAidGNoKCIrICIvWyIrICAiXmEtekEtWiIrICJdLyIrImcpPyIrICIubCIrImVuZyIrInRoIHwgMCIp)


f =  eval(atobZXZhbCgicyAgPSIrICAiPnMubWEiKyAidGNoKCIrICIvWyIrICAiXmEtekEtWiIrICJdLyIrImcpPyIrICIubCIrImVuZyIrInRoIHwgMCIp)

console.log(f("example"      )) // 0
console.log(f("3xampl3"      )) // 2
console.log(f("Hello, World!")) // 3
console.log(f("abc.def-"     )) // 2
console.log(f("     "        )) // 5
console.log(f("IT'S NORMAL"  )) // 2
console.log(f("•¥¥€???!!!"   )) // 10
console.log(f("abc\ndef"     )) // 1

console.log(f("eval(atobZXZhbCgicyAgPSIrICAiPnMubWEiKyAidGNoKCIrICIvWyIrICAiXmEtekEtWiIrICJdLyIrImcpPyIrICIubCIrImVuZyIrInRoIHwgMCIp)"))

s=>s.match(/[^a-zA-Z]/g)?.length|0

• You can save 2 Bytes using /[^a-z]/gi Jun 10 at 8:16
• @EphellonGrey The readable form is not submitted codes here. And this question is not a pure code-golf question.
– tsh
Jun 13 at 2:17
• technically, code-golf is the tiebreaker though
– Jo King
Jun 17 at 10:52
• @JoKing Yes, but you still need insert some spaces or something to it so its base64 encoded string doesn't contains [^a-z] characters. So make the readable form shorter doesn't mean golfer any way.
– tsh
Jun 18 at 9:24

# CJam, score 0, 9589 82 bytes

qeuWcibWcibKAbFbAbHbAbIbfbXfbKBbKbAbDbAbKbfbKYbKbYbCbfbXdfmdUfmOGYbCbfbUfbXfbUfbXb


Try it.

### Explanations

qeu                       e# Read input and convert to upper case.
65535b65535b              e# Convert to base 65535 and back, to cast characters to integers.
91fb                      e# Convert each element to base 91.
1fb                       e# Sum the digits in each element.
e# Only letters would end up greater than or equal to 65.
65fb                      e# Convert each element to base 65.
2220010939706446080fb     e# Convert each element from base 2.22e18.
1dfmd                     e# Divmod each element by floating point 1 to cast to floating point.
e# All letters would become the same number due to floating point inaccuracy.
e# It will also generate some extra 0s as the remainder but doesn't matter.
0fmO                      e# Cast elements back to integers.
20736fb0fb                e# Convert each element to base 20736 and get the last digit.
e# 20736 is a divisor of the number about 2.2e18,
e# so the last digit generated from a letter would be 0.
1fb0fb                    e# Convert each element to unary and get the last digit.
1b                        e# Sum the elements.


With the constants:

0        U
1        X
65       KBbKbAbDbAbKb    Convert 20 to base 11 (=19), from base 20 (=29), to base 10,
from base 13 (=35), to base 10, from base 20.
91       KAbFbAbHbAbIb    Convert 20 to base 10, from base 15 (=30), to base 10,
from base 17 (=51), to base 10, from base 18.
*170     AZbDb            Convert 10 to base 3 (=101), from base 13.
*196     GZbDb            Convert 16 to base 3 (=121), from base 13.
20736    GYbCb            Convert 16 to base 2, from base 12.
65535    Wci              Cast -1 to character, then back to integer.
2.22e18  KYbKbYbCb        Convert 20 to base 2, from base 20, to base 2, from base 12.

*Only used in an old version.


It depends on floating point inaccuracy. The number 2.22e18 won't change if a small number less than 26 is added to it.

CJam has a bug using divmod on a too big high precision integer and a float.

# Zsh, score 6, 64 bytes

tr -d abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ|wc -c

Attempt This Online!

• Ah yes, you're so right.
– CJK
20 hours ago

# Factor, score 5 (82 bytes)

readln "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"without length pprint


Try it online!

For once I can get a better score by reading from standard input!

# brainfuck, 110 bytes

+>>,[<++++[----->>->+>+<<<<]----[---->-<]>->+>[--<<-[<]<[>>>+<<]>>>]<<------>>>[--<<<-[<]<[>>>+<<]>>>>]<<<,]>.


Try it online!

Accepts input as ASCII. outputs as binary. The header adds 48 (ASCII 0) to the count so that small outputs appear as ASCII digits.

This is a complete rewrite of my previous answer below, taking into account everything I could have done better. In particular, I set up a specific cell with a 1 in it to help with the IF operation instead of trying to use other nonzero cells to assist.

There are a few more bytes to save with this approach if I have time later. It's still the highest scoring answer, but it isn't the longest anymore, which is gnerally as good as it gets with Brainfuck.

+>>                     Put a 1 in cell 0 then move to cell 2
,[                      take an input in cell 2 and loop until end of string marked by 0 encountered
<++++[----->>->+>+<<<<] Put 260 mod 256=4 in cell 1; iterate 260/5=52 times to subtract 52 from cell 3 and store 52 in cells 4 and 5
----[---->-<]>-         Put minus 4 = 252 in cell 1; iterate 252/4=63 times to subtract 63 from the input; then reduce by one more
>+>                     add 1 to cell 3
[--<<-[<]<[>>>+<<]>>>]  iterate 26 times UPPERCASE using 52 in cell 4; if not zero add 1 to cell 3
<<------>>>             subtract 6 from the input
[--<<<-[<]<[>>>+<<]>>>>]iterate 26 times LOWERCASE using 52 in cell 5; if not zero add 1 to cell 3
<<<                     overall cell 3 has increased by 0 if input is a letter or 1 if not a letter
,]                      take more input into cell 2 until end of string marked by 0 encountered
>.                      output count from cell 3


# brainfuck, 146 138 bytes

,[<++++[-----<-<+<+<+>>>>]>----------<<<<<[->>>>>-<<<<<]>>>>>--<<<<[-->>>>-[<]<[+>]<<<]>>->>------<<<[-->>>-[<]<[+>]<<]>++[->>>+<<<]>>,]>.


I misread the question and assumed all characters except AZazand newline should be counted. I now realise newlines need to be counted like any other non AZaz character which makes the code slightly shorter. If I had not considered newlines at all, the code might be shorter still, but the setup loop 260/5=52=2*26 is pretty efficient.

Try it online!

Accepts input as ASCII. outputs as binary. The header adds 48 (ASCII 0) to the count so that small outputs appear as ASCII digits.

Commented code

,[                        Take an input; If nonzero start looping
<++++                     Move left and add 4 to make (256+4)=260 mod 5
[-----<-<+<+<+>>>>]>      Loop 52 times to setup 3 cells with 52 and one with minus 52
----------<               Subtract 10 from input
<<<<[->>>>>-<<<<<]>>>>>-- Subtract another 52+2=54 from the input
<<<<[-->>>>-              Loop 52/2=26 times reducing the input by 1 each time for UPPERCASE
[<]<[+>]                If the input is nonzero increment the cell that contained minus 52
<<<]                      Ultimately the cell with minus 52 will be incremented 51 times for AZaz 52 for other
>>->>------               Subtract 1 from cell that contained minus 52 to avoid it reaching 0; and 6 from input
<<<[-->>>-                Loop 52/2=26 times reducing the input by 1 each time for LOWERCASE
[<]<[+>]                If the input is nonzero increment the cell that contained minus 52
<<]
>++                       Cell that contained minus 52 now has minus 2 for AZaz or minus 1 for other; increment by 2
[->>>+<<<]                Copy the value 0 or 1 into the final total
>>,]                      Take the next input and if nonzero continue to loop
>.                        Output the final total

• -146 score if you switch to one of those bf equivalents with words :P thanks for the bf answer! Jun 8 at 17:02

# Perl 5-F/[^a-z]/si -0, score 5 2 (6 bytes)

@DomHastings saves 3 points

say$#F  Try it online! Abusing the command line flags for all they're worth. The -F flag with its regex breaks the input apart on anything that isn't a letter and stores those fields in @F. -0 grabs all of the input at once (slurp mode). The actual code code assigns the last index of @F to$_ since there will always be at least one member of @F (assuming input is not null).

# Jelly, score 3, 4 bytes

@caird-coinheringaahing saves 1 byte!

ḟØẠL

Attempt This Online!

Explanation: Filter alphabetic characters from input, then return length

• None of ɠḟØẠ seem to be alphabetical characters, as defined by the question (and this program), so I think the score should probably be 4, not zero... Jun 9 at 21:37
• Jelly takes input through the command line arguments by default, so you can save 1 byte and make this work for any input by removing the ɠ: Try it online! Jun 9 at 21:40
• Thank you for the suggestions! It's my first time posting, apologies for not scoring correctly - I've updated my answer. Jun 10 at 0:33
• Also, wecome to Code Golf! Jun 10 at 1:15

# Wolfram Language (Mathematica), score 5, 39 bytes

sStringLength@s-Total@LetterCounts@s


Try it online!

Doesn't work if the input contains non-ASCII letters (e.g. այբուբեն).

The private-use character  is \[Function].

# Perl 5 + -n0 -M5.10.0, Score: 3, 14 bytes

say s M\PlMMig

Try it online!

• Score: 3,14 bytes lol pi Jun 9 at 8:49

# Alumin, Score 0 (82 bytes)

iqipkmddhhdtddtthaueyddhhhdtdhatveyddhhhhhhhdthhthcueydhhhdhathcdthavetrtahycmzfaf


Try it online! I thought this would be a funny submission, since it is almost impossible to get a score of anything more than 0 without introducing no-ops, since the only defined operations are the lowercase English alphabet. (Technically, you would use a space to separate two integer sequences in a row, but you can golf around that if necessary, and it didn't come up here.)

## Commented code

i                       PUSH INPUT CHARACTER
q                       WHILE TOP OF STACK > 0 {
i                         PUSH INPUT CHARACTER
p                       }
m                       MAP EACH STACK ELEMENT OVER {
OUR STACK CONSISTS OF JUST A CHARACTER
dd                        DUPLICATE INPUT TWICE
hhdtddttha                PUSH (2*2)*(2*2)*(2*2)+1
(AKA 65)
ue                        PUSH MAX(INPUT, 65) == INPUT
(AKA INPUT >= 65)
ydd                       DUPLICATE INPUT TWICE
hhhdtdhat                 PUSH (3*3)*((3*3)+1)
(AKA 90)
ve                        PUSH MIN(INPUT, 90) == INPUT
(AKA INPUT <= 90)
ydd                       DUPLICATE INPUT TWICE
hhhhhhhdthhthc            PUSH (7*7)*2-1
(AKA 97)
ue                        PUSH MAX(INPUT, 97) == INPUT
(AKA INPUT >= 97)
yd                        DUPLICATE INPUT ONCE MORE
hhhdhathcdtha             PUSH ((3*(3+1))-1)*((3*(3+1))-1)+1
(AKA 122)
ve                        PUSH MIN(INPUT, 122) == INPUT
(AKA INPUT <= 122)
STACK NOW LOOKS LIKE:
[B1 B2 B3 B4]
t                         PUSH AND(B3, B4)
r                         REVERSE STACK
[AND(B3,B4) B2 B1]
t                         PUSH AND(B2, B1)
a                         PUSH OR(AND(B3,B4), AND(B2, B1))
hyc                       PUSH NOT(^)
(AKA 0 FOR ALPHABETIC, 1 ELSE)
m                       }
zf                      FOLD ENTIRE STACK USING SEED 0 {
f                       }


Not 100% sure the constants are optimal, but for now I'm satisfied.

• right tool for the job :D Jun 10 at 4:09
• Hmm, now someone should do it in Minipyth. Jun 30 at 15:18

# Rust, score 14, 42 bytes

|s|s.replace(char::is_alphabetic,"").len()

Attempt This Online!

Only works for ASCII inputs, because str::len is counting bytes instead of characters.

# Retina 0.8.2, 55 bytes, score 3

[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]


Try it online! Link includes test suite, so final example with newline isn't included. Try it online! Final example only.

# Python 3, score 11, 39 bytes

lambda s:sum(not x.isalpha()for x in s)


Try it online!

# JavaScript (ES6), Score 13 (56 bytes)

s=>s.replace(/[abcdefghijklmnopqrstuvwxyz]/gi,'').length


Try it online!

# C# (Visual C# Interactive Compiler), 11 Score, 32 bytes

s=>s.Count(c=>!char.IsLetter(c))


Try it online!

# Wolfram Language (Mathematica), score 4, 40 bytes

ss~StringCount~Except@LetterCharacter


Try it online!

# Python 2, score 9, 40 bytes

lambda s:map(str.isalpha,s).count(False)


Try it online!

# APL (APLX) Score 6, 8 bytes

⍴⍞∼⎕A,⎕a


⍴ shape of…

⍞ input…

~ without…

⎕A upper case Alphabet…

, and

⎕a lowercase alphabet

# C (gcc), Score 16 (48 bytes)

main(c){return~c?!isalpha(c)+main(getchar()):c;}


Try it online!

# PowerShell Core, 59 bytes, score: 8 10

$input-replace"[abcdefghijklmnopqrstuvwxyz]"|foreach Length  Try it online! -2 bytes thanks to user314159 • You can drop the round brackets, the -join, the i from -ireplace, and the .Length property, and instead pipe the output to "ForEach-Object -MemberName Length" for a score of 8 and still 59 bytes: $input-replace"[abcdefghijklmnopqrstuvwxyz]"|foreach Length Jun 13 at 16:59