| Bytes | Lang | Time | Link |
|---|---|---|---|
| 038 | Janet | 250422T073503Z | xigoi |
| 035 | Raku Perl 6 rakudo | 250421T185105Z | xrs |
| 038 | Swift 6 | 250302T185427Z | macOSist |
| 068 | Jelly | 241129T013456Z | Unrelate |
| 024 | AWK F "" | 241127T202851Z | xrs |
| 014 | Uiua | 241001T213652Z | nyxbird |
| 015 | Uiua | 241001T215915Z | noodle p |
| 051 | Uiua # Experimental! | 240730T160016Z | Europe20 |
| 014 | Haskell + hgl | 240730T141436Z | Wheat Wi |
| 008 | Pip | 220608T225059Z | emanresu |
| 1264 | JavaScript ES6 | 220608T134706Z | Arnauld |
| nan | 221003T192638Z | bigyihsu | |
| nan | Fig | 221003T174516Z | Seggan |
| 023 | Japt v2.0a0 | 221003T162324Z | Shaggy |
| 026 | Perl 5 F/[^az]/si 0 | 220608T222549Z | Xcali |
| 032 | Alice | 220716T075712Z | Julian |
| 013 | Brev | 220621T122718Z | Sandra |
| 059 | PowerShell Core | 220610T010901Z | Julian |
| 067 | Ruby | 220617T130510Z | pxeger |
| 060 | BQN | 220617T102429Z | Mama Fun |
| 042 | Ruby | 220616T205525Z | TKirishi |
| 1648 | C gcc | 220608T221910Z | c-- |
| 008 | APL APLX Score 6 | 220611T235101Z | Adá |
| 031 | APL NARS2000 Score 19 | 220611T201745Z | jimfan |
| 005 | Japt | 220611T172415Z | Etheryte |
| 042 | Rust | 220609T032949Z | alephalp |
| 040 | Python 2 | 220610T112559Z | m90 |
| nan | CJam | 220610T063116Z | jimmy230 |
| 082 | Alumin | 220610T040802Z | Conor O& |
| 040 | Wolfram Language Mathematica | 220610T021753Z | att |
| 004 | Jelly | 220609T213214Z | sourlace |
| 110 | brainfuck | 220608T165952Z | Level Ri |
| 120 | JavaScript in Browser | 220609T091827Z | tsh |
| 014 | Perl 5 + n0 M5.10.0 | 220609T082838Z | Dom Hast |
| 032 | C# Visual C# Interactive Compiler | 220609T070538Z | dana |
| 039 | Wolfram Language Mathematica | 220609T031739Z | alephalp |
| 036 | Charcoal v | 220608T234252Z | Neil |
| 582 | Factor | 220608T224111Z | chunes |
| 009 | Burlesque | 220608T215800Z | DeathInc |
| 011 | Husk | 220608T142843Z | Dominic |
| 038 | R | 220608T191814Z | pajonk |
| 004 | Vyxal | 220608T135025Z | math sca |
| 081 | Haskell | 220608T131807Z | Wheat Wi |
| 1446 | Java | 220608T163826Z | Kevin Cr |
| 011 | Pyth | 220608T151121Z | math jun |
| 064 | Zsh | 220608T154152Z | pxeger |
| 039 | Python 3 | 220608T134334Z | m90 |
| 055 | Retina 0.8.2 | 220608T134109Z | Neil |
| 007 | 05AB1E | 220608T134018Z | Kevin Cr |
Janet, score 11 10, 28 38 bytes
(comp length(partial peg/find-all :A))
In Janet’s parsing expression grammar syntax, :A matches a non-alphabetic character. Interestingly, writing the code in a “point-free” style reduced the score by one despite significantly increasing the length.
Swift 6, 38 bytes, score: 14
{s in(s as String).count{!$0.isCased}}
Jelly, score 0, 366 68 bytes
LdLYYTYYJSpppppJLdLdLdLdLdLNCNCNCNCSSSSRUFNMHpOIFACHHNCHNCNCRTLrLLCN
Uses a New and Exciting™️ construction for obtaining the pivotal [155, 64] constant from 91, which just so happens to require \$O(n^5)\$ time and memory:
pppppJLdLdLdLdLdLNCNCNCNCSSSS Turn 91 into [155, 64]:
p Take the Cartesian product of [1 .. 91] with
the input (whose length I'll call L).
p Length: 91 * L.
p Do it again.
pp Length: 91 * L ** 2.
ppppp Do it a total of five times,
J using [1 .. L] once for chaining purposes.
pppppJL Take the length: 91 * L ** 5.
dL Divmod by L: [91 * L ** 4, 0].
dL Do it again: [[91 * L ** 3, 0], [0, 0]].
dL Do it a total of five times, vectorizing deeper
dL each time and creating a big old nested mess
dL of pairs totaling 32 "leaf" scalar elements
pJLdL all which are 0 except for one leftmost 91.
N Negate each leaf
C and subtract it from 1,
NC which is to say add 1 *to each leaf*,
NCNCNCNC four times.
S Sum the outermost pair
SSSS four times, leaving one remaining pair:
pJLdL [91, 0]
NCNCNCNC + (4
pppp dLdLdLdL SSSS * 2 ** 4)
pppppJLdLdLdLdLdLNCNCNCNCSSSS = [155, 64].
The Jelly interpreter as hosted on CPython absolutely is theoretically capable of running this program on itself--not the case with some of my earliest B-based attempts! MemoryErrors and OverflowErrors don't really keep you waiting--but you really, really don't want to. Fortunately, it is trivial to reduce the degree at the cost of length, removing one p, one dL, and one S to add four NCs, then eight, and so on, and doing so a maximal four times just brings you back to the vastly more performant previous revision:
Jelly, score 0, 366 365 200 194 172 bytes
LdLYYTYYJSpJLdLNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCNCRUFNMHpOIFACHHNCHNCNCRTLrLLCN
-1 remembering two golfs I'd thought of then abandoned two hours ago that cancel each other's problems/incompatibilities out
-165 by remembering I can divide by 2 before adding...
-6 with a little more goofier arithmetic
-22 realizing I can take distinct cumulative sums of integers with RUFNM, and that that's so powerful that it's worth having to go back to dividing by 2 only afterwards! (on account of the restriction to integers)
Relies extensively on the guarantee of non-empty input, allowing the length L to serve as a consistent positive integer that can math its way into making a handful of dyads not completely useless--aside from the underwhelming builtin set overall, the biggest weakness of ASCII-letter-only Jelly is the utter lack of any data-flow control whatsoever, rendering it completely impossible to combine two intermediate values if the right-hand one would be constructed by more than one builtin. However, most of the program is just spamming NC (negate then subtract from 1) as a vectorizing increment or CN as a vectorizing decrement--replacing those with normal additions or subtractions, we have:
LdLYYTYYJSpLLdL+64RUFNMH Construct the range midpoints:
L The length of the input (let's call it L)
dL divmod itself: [1, 0].
Y Join on newlines: [1, '\n', 0].
Y Join on newlines again: [1, '\n', '\n', '\n', 0].
T Truthy indices: [1, 2, 3, 4].
YY Join that on newlines, for a length of 13,
JS then sum [1 .. 13]: 91.
p Take the Cartesian product of that
Sp (implicitly converted to a 1-range) with
J the range from 1 to L inclusive,
L and take the length of that: 91 * L.
dL Divmod by L: [91, 0].
+64 Add 64: [155, 64].
R Convert both to 1-ranges
U descending,
F concatenate them,
N negate every element,
M and take maximal (i.e. -1) indices: [155, 219].
H Halve: [77.5, 109.5].
pOIFACHH‘H+2RTLrLL’ Count the characters outside the ranges:
p Take the Cartesian product of the midpoints with
O the codepoints of the input,
A and take the absolute value of
IF the difference of each pair.
C Subtract the differences from 1,
HH divide by 4,
‘ increment,
H halve,
+2 add 2,
R then finally convert to 1-ranges
RT which are empty if they're less than 1.
CHH‘H+2 (21-d)/8 < 1 iff d > 13.
TL Count the nonempty ranges:
pOIFACHH‘H+2RTL the number of characters *in* [A-Za-z].
rL Take the inclusive range from that to L,
L’ and subtract 1 from the length of that.
Yes, the 13th triangular number just so happens to also be 64 less than the sum of the codepoints of A and Z, i.e. twice their average which is 12.5 away from both of them, and that distance rounds up to 13. Wacky.
It feels like there might still be a cleverer way to construct the range midpoints using T or M, but the best I could think of so far was just Y spam that gets binary digits from the length of a list larger than the Jelly interpreter is capable of constructing, and at this point it might not beat 68.
If all Unicode characters with the Letter property counted as alphabetic, nŒsCS would be score 0 and 5 bytes, but rely heavily on the guarantee that the only non-ASCII characters in the input are the ones in the program--it counts the characters that don't change when case-swapped, but not all letters have case variants. Constructing a Python expression to access the unicodedata module with only letters could also be pretty entertaining itself...
AWK -F "", 13 score, 24 bytes
$0=NF-gsub(/[A-Za-z]/,x)
awk -F "" '$0=NF-gsub(/[A-Za-z]/,x)' <<< 890eee
$0= # set output
NF # number of chars
-gsub( # returns number of matches
/[A-Za-z]/, # regex
x) # placeholder
Uiua, 0 score, 14 bytes
firunwheabssig
Formats to ⊢°⊚⌵±.
⊢°⊚⌵±
± # case of character (-1/1 for lower/uppercase, 0 for non a-z)
⌵ # absolute value (1 for a-z, 0 for non a-z)
°⊚ # counts of 0s and 1s
⊢ # get first (count of 0s)
Uiua, score 0, 15 bytes
redaddnotabssig
Try it: Uiua pad. Upon running, the code will be formatted to the following:
/+¬⌵±
This is because Uiua lets you type all of its glyphs using just alphabetical characters by using any prefix of that glyph's name 3 characters or longer. Some glyphs let you use 2 character prefixes, or even just the first letter in certain scenarios, but none of the ones used here do.
Explanation: the sign of a character gives -1 for lowercase letters, 1 for uppercase, and 0 for non-alphabet. Taking the absolute value of this gives 1 for alphabet and 0 for non-alphabet, and taking not of this gives the opposite. Then we reduce this list by addition, giving the total number of ones.
Uiua # Experimental!, score 0, 85 73 56 51 bytes
firunwhememdipabsaddranceipowetaaddtauetastringifyA
Formats to ⊢°⊚∈⊙⌵+⇡⌈ⁿη+τηstringifyA.
Haskell + hgl, score 2, 14 bytes
cn$n<isAlpha
Checks the number of characters not satisfying isAlpha.
isAlpha has a short version α, but that's not an alphabetic character according to the definition in the question, so while it would shorten things it would increase score. n < isAlpha is implemented as a function nα which would shorten things without increasing score, however the issue is that according to unicode α is an alphabetic character, and nα follows unicode's definition, not the challenge's. This is fine until we actually include α in the answer at which point it becomes wrong.
Alternate, score 2, 59 bytes
cna"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Reflection
Since this isn't a code-golf challenge it's not the most useful to reflect on this. I'm not going to say for example that α should be renamed for this challenge. In light of that however, I still have some thoughts.
The optimal (reasonable) score here is probably 1. There are a couple of reasonable ways this could happen:
- There should probably be a builtin for the entire uppercase and lowercase alphabet. If it didn't contain special unicode characters, then we'd have a score one answer with
cna alf. - There should be a builtin for
cn<(n<), every other variant ofcnhas this, it's just frustratingly not present here. If it existed thencnN isAlphawould score 1. - There could be deprecated names for the negative character functions like
isNotAlpha. This would improve usability a little bit in general and save us 1 score on this challenge.
Pip, score 0, 8 bytes
oMSaRMXA
-3 thanks to DLosc.
RM # Remove...
XA # Letters
a # From input
MS # Sum result when mapping each to...
o # 1
JavaScript (ES6), Score 12 (64 bytes)
-1 point thanks to @l4m2
s=>s.replace(/[abcdefghijklmnopqrstuvwxyz]/gi,new String).length
Go, score 30, 85 bytes
import."unicode"
func f(s[]rune)(c int){for _,e:=range s{if!IsLetter(e){c++}}
return}
Perl 5 -F/[^a-z]/si -0, score 5 2 (6 bytes)
@DomHastings saves 3 points
say$#F
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. Therefore, there is one element added to @F for each nonalphabetic character. -0 grabs all of the input at once (slurp mode). The actual code code outputs the last index of @F since there will always be at least one member of @F (assuming input is not null).
Alice, 32 bytes, score 24 9
/qlqaq"q&qcqqqo
qIq"qzqrq-q/d\q@
Explanation
All the q are useless and replace spaces to lower the score, leaving us with the following:
/ Switch to ordinal mode
Il Read the input, lowercase
"az"r Build the alphabet string
&- For each character of the alphabet, remove it from the input
c Split into characters
/ Back to cardinal mode
d Get the depth of the stack (the remaining characters non a-z)
\o@ Print the depth
Brev, score 13
((fn (string-length (strse x 'alpha ""))) "(fn(string-length(strse x 'alpha \"\")))")
PowerShell Core, 59 bytes, score: 8 10
$input-replace"[abcdefghijklmnopqrstuvwxyz]"|foreach Length
-2 bytes thanks to user314159
Ruby, score 5, 67 bytes
p gets.count"^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
BQN, Score: 8, 60 bytes
+´¬∘∊⟜"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Thanks to @thejonymyster for helping halve the score!... Of course at the cost of tripling the byte count ;D
Explanation
¬∘∊⟜"..."replace each char in input with 0 if alphabetical, 1 otherwise+´sum occurrences of 1
Ruby, Score: 24, 42 bytes
->s{s.chars.map{_1=~/[A-Za-z]/?0:1}.sum-1}
There is a -1 the end due to the \n. If you don't coun't it, it's 40 bytes and Score: 22
APL (APLX) Score 6, 8 bytes
⍴⍞∼⎕A,⎕a
⍴ shape of…
⍞ input…
~ without…
⎕A upper case Alphabet…
, and
⎕a lowercase alphabet
APL (NARS2000) Score 19, 31 bytes
{≢⍵~⎕av[C,32+C←66..91]}
Examples
{≢⍵~⎕av[C,32+C←66..91]} 'Hello, World!' evaluates to 3
{≢⍵~⎕av[C,32+C←66..91]} '•¥¥€???!!!' evaluates to 10
How it works
⎕av[C,32+C←66..91] generates the alphabetic string from built-in ⎕av array. ~ performs set difference with right argument ⍵. ≢ counts number of element in the set difference.
Score of this expression could be determined by applying it to itself:
⎕fmt {≢⍵~⎕av[C,32+C←66..91]} '{≢⍵~⎕av[C,32+C←66..91]}' evaluates to 19.
Japt, score: 2, 5 bytes
;eF l
; // Alternative initial variables, where F = "[A-Za-z]".
eF // Replace all occurrences of F in input with default value of empty string.
l // Return the result's length.
Rust, score 14, 42 bytes
|s|s.replace(char::is_alphabetic,"").len()
Only works for ASCII inputs, because str::len is counting bytes instead of characters.
CJam, score 0, 95 89 82 bytes
qeuWcibWcibKAbFbAbHbAbIbfbXfbKBbKbAbDbAbKbfbKYbKbYbCbfbXdfmdUfmOGYbCbfbUfbXfbUfbXb
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.
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 }
k DISCARD EOF
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 {
a ADD TOP TWO
f }
Not 100% sure the constants are optimal, but for now I'm satisfied.
Wolfram Language (Mathematica), score 4, 40 bytes
ss~StringCount~Except@LetterCharacter
Jelly, score 3, 4 bytes
@caird-coinheringaahing saves 1 byte!
ḟØẠL
Explanation: Filter alphabetic characters from input, then return length
brainfuck, 110 bytes
+>>,[<++++[----->>->+>+<<<<]----[---->-<]>->+>[--<<-[<]<[>>>+<<]>>>]<<------>>>[--<<<-[<]<[>>>+<<]>>>>]<<<,]>.
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.
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
JavaScript (in Browser), Score 4, 120 bytes
eval(atob`ZXZhbCgicyAgPSIrICAiPnMubWEiKyAidGNoKCIrICIvWyIrICAiXmEtekEtWiIrICJdLyIrImcpPyIrICIubCIrImVuZyIrInRoIHwgMCIp`)
f = eval(atob`ZXZhbCgicyAgPSIrICAiPnMubWEiKyAidGNoKCIrICIvWyIrICAiXmEtekEtWiIrICJdLyIrImcpPyIrICIubCIrImVuZyIrInRoIHwgMCIp`)
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(atob`ZXZhbCgicyAgPSIrICAiPnMubWEiKyAidGNoKCIrICIvWyIrICAiXmEtekEtWiIrICJdLyIrImcpPyIrICIubCIrImVuZyIrInRoIHwgMCIp`)"))
In readable form:
s=>s.match(/[^a-zA-Z]/g)?.length|0
C# (Visual C# Interactive Compiler), 11 Score, 32 bytes
s=>s.Count(c=>!char.IsLetter(c))
Wolfram Language (Mathematica), score 5, 39 bytes
sStringLength@s-Total@LetterCounts@s
Doesn't work if the input contains non-ASCII letters (e.g. այբուբեն).
The private-use character is \[Function].
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.
Factor, score 5 (82 bytes)
readln "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"without length pprint
For once I can get a better score by reading from standard input!
Burlesque, Score 0, 9 bytes
qrdfnsait
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
Husk, Score 0, 13 11 bytes*
mLfopVDkDma
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!
R, score 9, 38 bytes
function(x)sum(!tolower(x)%in%letters)
Takes input as a vector of characters.
R, score 14, 85 bytes
function(x)nchar(gsub("[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]","",x))
Takes input as a proper string.
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
Haskell, score 6, 81 bytes
length.filter(flip notElem"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
The non-alphabetic characters are .( "").
Also score 6, but 4 bytes longer is:
fmap length$filter$flip notElem"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
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.
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
Pyth, Score 0, 14 11 bytes
lfqZhxGrTZQ
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
Zsh, score 6, 64 bytes
tr -d abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ|wc -c
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.
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
Try it online or verify all test cases.
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)