5
\$\begingroup\$

Challenge (Easy)

Write a function which takes an argument and returns the number of non-alphanumeric characters found.

Challenge (Hard)

Write a function which takes an argument and returns the number of bytes used to store the number of non-alphanumeric characters found. (ie: include calculation for multi-byte characters.)

Rules / Notes

  • Alphanumeric in this case is defined as:

    abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789

  • A null character should count as 0 characters, but as 1 byte when stored.

    NUL

  • Showing multi-byte support (if too complicated) only has to demonstrate one character set or language reference / codepage (if this actually matters. I don't know, so just putting it out there.)

Winner

Since this is code golf, the shortest code that correctly matches the challege wins.

\$\endgroup\$
3
  • \$\begingroup\$ Require to support multibyte char? Require UTF8? \$\endgroup\$
    – l4m2
    Commented May 4, 2018 at 2:06
  • \$\begingroup\$ For C non-unicode they are just same challenge? \$\endgroup\$
    – l4m2
    Commented May 4, 2018 at 2:07
  • \$\begingroup\$ @l4m2 "Showing multi-byte support (if too complicated) only has to demonstrate one character set or language reference / codepage" \$\endgroup\$
    – mbomb007
    Commented May 4, 2018 at 18:10

20 Answers 20

5
\$\begingroup\$

Perl, 14 characters

y/A-Za-z0-9//c
\$\endgroup\$
2
\$\begingroup\$

Stax, 3 bytes (Easy)

├Dr

Run and debug it

Explanation

VL-%        # Full program, unpacked
VL          # Push "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  -         # Remove all elements in b from a.
    %       # Length and implicitly print result
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Dang, ninja'd me by a minute! My solution was identical. I'd describe VL as "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" rather than as many separate elements. \$\endgroup\$ Commented May 4, 2018 at 18:06
  • \$\begingroup\$ @Scrooble Yeah that is what I had it as originally, but I thought it looked too long, so I formatted it like that to be more concise. I see how they could be viewed at differently. I'll change it to be like you recommended though. \$\endgroup\$
    – Multi
    Commented May 4, 2018 at 18:08
2
\$\begingroup\$

Jelly, 7 6 4 bytes

ḟØBL

Try it online!

ḟØBL
ḟ         reverse ḟilter: remove all of the input characters that are also in...
 ØB       alphanumeric characters...
   L      and get the Length of the resulting string!

6-byte solution:

ḟØWṖ¤L

Try it online!

ḟØWṖ¤L
ḟ         reverse ḟilter: remove all of the input characters that are also in...
 ØWṖ¤     the "word" character class with the underscore popped from it, taken as a nilad...
     L    ...and take the length of the resulting string
\$\endgroup\$
5
  • 2
    \$\begingroup\$ You can use (nilad) (links) ¤ as a new nilad, like so: ḟØWṖ¤L \$\endgroup\$
    – lynn
    Commented May 4, 2018 at 14:04
  • 1
    \$\begingroup\$ Alternatively, ØWṖ⁸ḟL works too, of course. (That ⁸ḟ is the fourth monad chain pattern.) \$\endgroup\$
    – lynn
    Commented May 4, 2018 at 15:00
  • \$\begingroup\$ @Lynn Thank you! I wasn't able to understand ¤ from the docs before but now I understand it! \$\endgroup\$
    – habs
    Commented May 4, 2018 at 15:35
  • 1
    \$\begingroup\$ You can use ØB (push '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz') instead of ØWṖ¤ to save 2 bytes. \$\endgroup\$ Commented May 4, 2018 at 18:42
  • \$\begingroup\$ @KevinCruijssen, thanks! Don't know why I didn't catch that nilad when I was making this. \$\endgroup\$
    – habs
    Commented May 4, 2018 at 19:51
1
\$\begingroup\$

D

easy (29 chars)

count!"!isAlphaNum(b)&&b"(s);

hard (35 chars)

s needs to be a char[]

s.length-count!"!isAlphaNum(b)"(s);
\$\endgroup\$
1
\$\begingroup\$

Groovy

Easy: 26 25 30 characters

c={(it=~/[[^\00\w]_]/).size()}

assert c("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789")== 2
assert c("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")==0
assert c("a-b-7*NNuah ~#77%")==7
assert c('_|') == 2
assert c('\0') == 0

Hard: 47 characters

s={it.replaceAll(/[\w&&[^_]]/,'').bytes.size()}

assert s("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789")== 2
assert s("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")==0
assert s("a-b-7*NNuah ~#77%")==7
assert s('_') == 1
\$\endgroup\$
7
  • \$\begingroup\$ Is that | supposed to be in the first regex? \$\endgroup\$ Commented Nov 17, 2011 at 8:32
  • \$\begingroup\$ I thought it was... but looks unnecessary :) thanks \$\endgroup\$
    – Armand
    Commented Nov 17, 2011 at 9:05
  • \$\begingroup\$ Looked to me like a bug, because I think it would have messed up the counts in strings with a |. \$\endgroup\$ Commented Nov 17, 2011 at 9:50
  • \$\begingroup\$ Waiting for some other entries, but nice go at it. Have you tried running some Chinese or Japanese characters into the hard function to see if it counts them properly? \$\endgroup\$
    – cbroughton
    Commented Nov 17, 2011 at 21:18
  • \$\begingroup\$ I don't see you handling '\0' in easy (they should also be excluded) \$\endgroup\$ Commented Nov 18, 2011 at 0:29
1
\$\begingroup\$

Husk, 4 bytes (easy)

#(¬□

Try it online!

Explanation

Pretty simple usage of isanum ():

#(¬□)  -- example: "Input!"
#(  )  -- count number of
 ( □)  -- | is alphanumeric: [73,110,112,117,116,0]
 (¬ )  -- | not: [0,0,0,0,0,1]
       -- : 1
\$\endgroup\$
1
\$\begingroup\$

R, 68 42 bytes

-26 bytes thanks to Giuseppe.

function(x)nchar(gsub('[[:alnum:]]',"",x))

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

05AB1E, 4 bytes (easy)

žKмg

Try it online.

Explanation:

žK      # Push "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  м     # Remove all occurrences of this second string from the input string
   g    # Push and implicitly output the length of the result

05AB1E, 19 bytes (hard)

žKмÇεDžy‹i1ë.²<5÷>н]O

Thanks to @Mr.Xcoder for helping me put two sub-solutions together with D, and explaining how ] closes both the if-statement and foreach-loop. (I accidentally placed the D before the ε and used one } instead of two..)

Try it online.

Explanation:

žK                     # "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  м                    # Remove all occurrences of this second string from the input string
   Ç                   # Convert each character to its unicode value
    εD                 # Foreach over this list
         i             #  If the current item
        ‹              #  is maller than
      žy               #  128
          1            #   Use 1
           ë           #  Else
            .²         #   Use log_2
              <        #   minus 1
               5÷      #   integer-divided by 5
                 >     #   plus 1
                  н    #  Take the head of the sublists
                   ]   # Close both the if-else and for-each (shorter version of `}}`)
                    O  # Sum everything together

05AB1E doesn't have any builtins for knowing the amount of bytes a character costs, so I'm converting them to unicode values with Ç and use the following pseudo-code to determine their bytes:

if(unicodeValue < 128)
  return 1
else
  return log_2(unicodeValue-1)//5+1    # (where // is integer-division)

Pseudo-code inspired by @TheBikingViking's Python 3 answer for the Bytes/Characters challenge.

\$\endgroup\$
1
\$\begingroup\$

MS-SQL, 85 bytes (easy)

SELECT SUM(1)FROM spt_values,t
WHERE type='P'AND SUBSTRING(v,number,1)LIKE'[^a-z0-9]'

Handles strings up to 2047 characters. Per our IO standards, input is taken via a pre-existing table t with varchar field v.

This must be run in the master database (which exists on every SQL server). This database has a system table dbo.spt_values, which, if we filter by type='P', contains counting numbers from 0 to 2047. Join that to our input table to split each character into its own row, then count up those that match the LIKE filter (which supports character ranges).

MS-SQL, 85 bytes (hard)

SELECT SUM(2)FROM spt_values,t
WHERE type='P'AND SUBSTRING(v,number,1)LIKE'[^a-z0-9]'

You also need to change the input table to an nvarchar field v instead of varchar.

So yeah, this is kind of cheaty, because the nvarchar data type uses 2 bytes for every character, even for normal ASCII characters. That means I don't have to distinguish between characters that could be stuffed into a single byte and those that can't. But it does strictly satisfy the challenge, since it reflects the number of bytes that SQL is actually using to store nvarchar strings.

\$\endgroup\$
0
\$\begingroup\$

Javascript 1.8

easy (48 chars)

function f(s)(s.match(/[^a-z0-9]/gi)||[]).length

\$\endgroup\$
0
\$\begingroup\$

PowerShell, easy, 44

filter e{($args-replace"[a-z0-9]").Length}

If we stretch the definition of »arguments«, we can shorten it a bit more (41):

filter e{($_-replace"[`0a-z0-9]").Length}

but it then requires input to be sent via the pipeline.

PowerShell, hard, 71

function x{[text.encoding]::utf8.GetByteCount($args-replace'[a-z0-9]')}

Again, if we allow the pipeline we get it to 68:

function x{[text.encoding]::utf8.GetByteCount($_-replace'[a-z0-9]')}
\$\endgroup\$
0
\$\begingroup\$

Scala

Easy (43 chars)

def c(s:String)=s.count(!_.isLetterOrDigit)

Hard (58 chars)

def c(s:String)=s.filter(!_.isLetterOrDigit).getBytes.size
\$\endgroup\$
0
\$\begingroup\$

Python

easy (39 chars)

f=lambda s:sum(1-i.isalpha()for i in s)
\$\endgroup\$
1
  • \$\begingroup\$ You can remove the f= to save 2 bytes \$\endgroup\$ Commented Apr 2, 2017 at 23:18
0
\$\begingroup\$

Brainfuck

Easy (1397 chars)

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

All hand coded. It takes input until it gets a 0xA character signifying end of input (not counted). Only handles up to 255 nonalphanumeric input characters.

\$\endgroup\$
0
\$\begingroup\$

Perl (easy) 27 characters

sub _{$_=shift;(s/\W|_//g)}

usage:

say _('@abc_123ABC -("~ abc')   
---> 8
\$\endgroup\$
0
\$\begingroup\$

Ruby, easy, 32

f=->s{s.scan(/[^a-z0-9]/i).size}
\$\endgroup\$
0
\$\begingroup\$

Gol><>, Easy, 26 bytes

iEh$"0:A[a{"{16F@2k)S^|}~+

Try it online!

How it works

iEh$"0:A[a{"{16F@2k)S^|}~+

iEh                         Take input as char; if EOF, print the top as int and halt
   $                        Move the input under the char counter
    "0:A[a{"                Push six boundary chars
            {1              Pull the input to the top, and push 1 (XOR counter)
                            (Stack: [char counter, ...boundary, input, XOR counter])
              6F      |     Repeat 6 times...
                @             Pull a boundary char to the top
                 2k)          Copy the input char and compare (boundary > input)
                    S^        XOR with the XOR counter
                            (Stack: [char counter, input, XOR counter])
                       }~+  Move XOR counter to bottom, discard input, and
                              add to the char counter
                            Repeat indefinitely
\$\endgroup\$
0
\$\begingroup\$

Pyth

Easy, 17 bytes

l:z"[a-zA-Z0-9]"k

Try it online!

Hard, 30 bytes

/lsm.[\08.BCd:z"[a-zA-Z0-9]"k8

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Java 10, 42 bytes (easy)

s->s.replaceAll("[A-Za-z0-9]","").length()

Try it online.

Explanation:

s->                               // Method with String parameter and integer return-type
  s.replaceAll("[A-Za-z0-9]","")  //  Remove all digits and letters
   .length()                      //  And return the length

Java 10, 102 bytes (hard)

s->{int r=0;for(var c:s.replaceAll("[A-Za-z0-9]","").split(""))r+=c.getBytes("utf8").length;return r;}

Try it online.

Explanation:

s->{                              // Method with String parameter and integer return-type
  int r=0;                        //  Result-integer, starting at 0
  for(var c:s.replaceAll("[A-Za-z0-9]","")
                                  //  Remove all digits and letters
             .split(""))          //  And loop over the remaining characters
    r+=                           //   Add to the result-sum:
      c.getBytes("utf8").length;  //    The UTF-8 bytes of the current character
  return r;}                      //  Return the result-sum
\$\endgroup\$
0
\$\begingroup\$

Haskell, 58 52 bytes (easy)

-6 bytes, thanks to Laikoni (inverting the test, using elem instead)!

f s=sum[1|c<-s,elem c":;<=>?@[\\]^_`"||c>'z'||c<'0']

Try it online!

\$\endgroup\$
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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