Count rotary dial pulses in a phone number (including letters)

05AB1E, 19 18 17 15 bytes


Try it online!

This is the first answer to use π. Why use π, you might ask? Well, the letters are associated with 22233344455566677778889999, in order. Notice how most digits repeat 3 times, but 7 repeats 4 times. You could say that each digit repeats (3+1/7) times, on average. I wonder if there’s any number that’s approximately 3+1/7 and takes fewer bytes than 22/7…

This only gives 4 7s, not 4 9s, so we still need to handle Z as a special case.

A               # alphabet (abcdefghijklmnopqrstuvwxyz)
 Á              # rotate right (zabcdefghijklmnopqrstuvwxy)
  0ª            # append 0 (zabcdefghijklmnopqrstuvwxy0)

ā6+             # range [7..33]
   žq÷          # divide by π (22233344455566677778889991010)
      9š        # prepend 9 (922233344455566677778889991010)

‡               # transliterate the implicit input with the two lists above
                # this replaces z → 9, a → 2, … y → 9, 0 → 10
 þ              # remove all non-digits
  O             # sum

C# (Visual C# Interactive Compiler), 51 bytes


Saved 1 byte thanks to @recursive

Saved 10 bytes thanks to @ExpiredData's observation that only () +-/. will be in the input

Try it online!

n =>                     // Function taking input as string
  n.Sum(x =>             // Map each value 'x' through the following
    x>64 ?               //   If 'x' is an uppercase letter
      (x-59-x/83-x/90)/3 //     Take each char's ASCII value subtracted by 59, and subtract
                         //     one if the char is 'S' and one if the char is 'Z'
    : x>47 ?             //   Else if the char is a digit
      1-~x%~9            //   Take 1 - (-x - 1) % -10 (Maps 0 to 10, and 1-9 to themselves
    : 0                  //   Else, 0
  )                      // And sum it all up, then return it

Python 2, 74 bytes

lambda s:sum([(n-59-n/83-n/90)/3,1-~n%~9][n<58]for n in map(ord,s)if n>47)

Try it online!

Does some arithmetic on the ASCII value for each character. The first option checks for letters and the second options checks for numbers. The clarification that all punctuation characters allowed in the input are ones with ASCII values less than 48 let me simplify the logic, but a new method altogether might now be better.

Python 2, 84 bytes

lambda s:sum(1+'1xxxx2ABCx3DEFx4GHIx5JKLx6MNOx7PQRS8TUVx9WXYZ0'.find(c)/5for c in s)

Try it online!

Uses a hardcoded lookup string, with each block of 5 characters corresponding to the characters giving each value starting with 1. Blank spaces are filled with x, which can't be in the input which is capitalized. Fortuitously, characters not appearing in the string produce -1 for the .find which gives a summand of zero.