1

Hi all I am pretty new to python coding but have recently stumbled upon a problem, when asking people for names the program will allow numbers, is there a simple way to fix this.

My code is something like this:

print("what is your name?")

name=input()

print("thank you",name,".")

I am not entirely sure that is the exact code but it does those three things. Thank you and sorry it is a bit basic. Also I am using 3.3.2 I think.

Ash
  • 31
  • 1
  • 1
  • 2

2 Answers2

7

You can use str.isalpha to test if a string is all alphabetic characters (letters):

>>> 'abcde'.isalpha()
True
>>> 'abcde1'.isalpha()
False
>>>

If you have a specific character set to test for, you can use all and a generator expression:

chars = set('abcde')  # Put the characters you want to test for in here
all(c in chars for c in name)

Also, I used a set instead of a regular string of characters to improve efficiency. Sets have O(1) (constant) complexity with in where as strings have O(n) (linear) complexity. In other words, it is faster to find things in a set than in a string.


Lastly, you can use string.ascii_letters instead of typing out the whole alphabet:

>>> from string import ascii_letters
>>> ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>>

This becomes especially useful if you want to test for all the letters of the alphabet plus another character or so (such as a hyphen):

chars = set(ascii_letters + '-')
  • The second would probably be better since isalpha will not work for hyphens – Thorin Schmidt Dec 10 '14 at 21:45
  • Good point. I've edited my answer to handle hyphens. –  Dec 10 '14 at 21:50
  • @iCodez : Except that since the string has a fixed and known size, the actual search complexity is O(1) with regard to the `name` string. – njzk2 Dec 10 '14 at 21:50
  • if the OP just wants to just check for numbers `if not any(x.isdigit() for x in s)` and allow all other characters – Padraic Cunningham Dec 10 '14 at 21:53
  • @njzk2 - No it isn't. Doing `char in string` is always `O(n)` because `in` has to go through the string character by character until it finds what it is looking for. Sets however have `O(1)` complexity because they use a hash-lookup. –  Dec 10 '14 at 21:54
  • @PadraicCunningham - True. But I went with my approach because he said he is working with names. Using your approach, a user could enter symbols such as `$` or `%`, which are not a part of a normal name. –  Dec 10 '14 at 21:55
  • Time complexity seems quite irrelevant in this case, since n is going to be approximately zero, plus some epsilon (let's say ~60, ascii chars plus some punctuation and whitespace). – Jon Kiparsky Dec 10 '14 at 23:30
  • @JonKiparsky - I agree that it isn't a *huge* improvement, but it seems better that `chars` be a set. I mean, `chars` is supposed to represent the set of characters to test for. So, why not make it a set? Also, for a one-time run, you won't get anything significant. However, you will surely notice the performance gain of the `O(1)` algorithm if you use this code repeatedly in a loop. –  Dec 10 '14 at 23:36
  • 1
    @iCodez No, I don't think you will, considering the case we're describing. The slowest element in this equation is the user, and there's not a lot of ways you can make time an issue. – Jon Kiparsky Dec 10 '14 at 23:40
  • @iCodez: `char in string` is O(n) where `n` is the size of the string. In this case, the string size is always 52, which is a constant. O(constant) = O(1). `n` is the size of the variable input `name`. – njzk2 Dec 11 '14 at 01:50
0

There are a couple of ways to address this. One would be to do something like

if name.isalpha():
  # it's alphabetic
else:
  # it's not - prompt for new input

But this will reject some names that you might like, such as "John Smith" or "Kate O'Conner".

A more careful approach would be something like

if any(map (lambda c: c.isdigit(), name)):
  # there's a digit in there, reject it
else:
  # it's got no digits, but maybe it still has punctuation that you don't want?
  # do further checks as needed

You can also build a whitelist:

import string
allowed_chars = string.ascii_letters+"'"+ "-" + " "  
   # allow letters, single-quote, hyphen and space
if all([c in allowed_chars for c in name]):
  # passes the whitelist, allow it
Jon Kiparsky
  • 7,499
  • 2
  • 23
  • 38