3

Writing a program that prompts the user to enter a social security number in the format ddd-dd-dddd where d is a digit. The program displays "Valid SSN" for a correct Social Security number or "Invalid SSN" if it's not correct. I nearly have it, just have one issue.

I'm not sure how to check if it's in the right format. I can enter for instance:

99-999-9999

and it'll say that it's valid. How do I work around this so that I only get "Valid SSN" if it's in the format ddd-dd-dddd?

Here's my code:

def checkSSN():
ssn = ""
while not ssn:  
    ssn = str(input("Enter a Social Security Number in the format ddd-dd-dddd: "))
    ssn = ssn.replace("-", "") 
    if len(ssn) != 9: # checks the number of digits
        print("Invalid SSN")
    else:
        print("Valid SSN")
Blue Ice
  • 7,888
  • 6
  • 32
  • 52
user3105664
  • 179
  • 3
  • 6
  • 11

4 Answers4

9

You can use re to match the pattern:

In [112]: import re

In [113]: ptn=re.compile(r'^\d\d\d-\d\d-\d\d\d\d$')

Or r'^\d{3}-\d{2}-\d{4}$' to make the pattern much readable as @Blender mentioned.

In [114]: bool(re.match(ptn, '999-99-1234'))
Out[114]: True

In [115]: bool(re.match(ptn, '99-999-1234'))
Out[115]: False

From the docs:

'^'
(Caret.) Matches the start of the string, and in MULTILINE mode also matches immediately after each newline.
'$'
Matches the end of the string or just before the newline at the end of the string

\d
When the UNICODE flag is not specified, matches any decimal digit; this is equivalent to the set [0-9].
zhangxaochen
  • 32,744
  • 15
  • 77
  • 108
2

Without using regular expressions I'd suggest a straightforward way:

def checkSSN(ssn):
    ssn = ssn.split("-")
    if map(len, ssn) != [3,2,4]:
        return False
    elif any(not x.isdigit() for x in ssn):
        return False
    return True

Two-liner with all things collapsed together:

def checkSSN(ssn):
    ssn = ssn.split("-")
    return map(len,ssn) == [3,2,4] and all(x.isdigit() for x in ssn)

Note: if you are using Python 3, you'll need to convert map to list: list(map(...))

sashkello
  • 17,306
  • 24
  • 81
  • 109
  • You can simplify your code a little bit by setting some return variable to False before your case statement, and then only setting it to true if all conditions are accepted. Reference my answer for the pattern: we basically took the same strategy except yours more elegantly uses a `map` call. Also as a general rule of thumb, you should avoid having multiple `return` statements in a single function. – David Marx Mar 06 '14 at 05:06
  • @DavidMarx True, mate. Don't see a reason for editing my answer into almost exactly your answer though. My purpose was kind of a clear line-by-line way of guiding the OP through logic, rather than writing a pretty piece of code :) – sashkello Mar 06 '14 at 05:08
  • 1
    Do you need the first condition `len(ssn) != 3`? That looks like it can be covered by the `map(len, ssn) != [3,2,4]` condition. – Pandu Mar 06 '14 at 05:28
2

How about this:

SSN = raw_input("enter SSN (ddd-dd-dddd):")
chunks = SSN.split('-')
valid=False
if len(chunks) ==3: 
   if len(chunks[0])==3 and len(chunks[1])==2 and len(chunks[2])==4:
       valid=True
print valid
David Marx
  • 8,172
  • 3
  • 45
  • 66
  • This is a really simple (and therefore good) implementation to handle this without a regex! Good call David! – Brad Cypert Mar 06 '14 at 05:32
  • @user3105664 This doesn't check if `d` is a digit. If there are some letters, this will still return True. – sashkello Mar 06 '14 at 05:35
  • 1
    yup. I appreciate the "accept" but really sashkello has the more elegant and thorough non-regex solution. But there's nothing special about not using regular expressions: zhangxaochen really has the best solution. – David Marx Mar 06 '14 at 05:37
0

I'd like to add an answer using regex and python3

import re

# Tests
data = [
    "enter SSN (989-45-8524):",
    "456748965", 
    "e43-45-7845", 
    "***-**-4598", 
    "4-98-4589", 
    "Social security Number is: [783-65-7485]", 
    458859635, 
    " Some text"
]

for ssn in data:
    # Grab only digit and check length of string. 
    # This line is the magik
    _ssn = "".join(re.findall(r"[\d]+", str(ssn)))

    if len(_ssn) == 9:
        print(ssn, f"{_ssn} is valid!")


Wolfgang Leon
  • 695
  • 9
  • 20