I'm trying to make a program that takes a postal code input from the user and checks to see if it's valid. So far I have:
postalCode = input("Postal code: ")
postalCode = postalCode.replace(" ", "")
postalCode = postalCode.lower()
letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
valid = True
for i in range(0, len(postalCode), 2):
if postalCode[i] not in letters or postalCode[i+1] not in numbers:
valid = False
break
if(valid):
print("Valid postal code.")
else:
print("Not a valid postal code.")
The code runs fine, but I know using expressions would be much more viable but I haven't been able to figure out how they work.
The Canadian postal code format is: L/N/L N/L/N
Thanks
No regex Solution:
Get your facts straight - a-z is wrong, some letters are omitted due to similarity:
A Neufundland B Nova Scotia C Prince Edward Island
E New Brunswick G Québec-Ost H Montréal und Laval
J Québec-West K Ontario-Ost L Ontario-Mitte
M Groß-Toronto N Ontario-Südwest P Ontario-Nord
R Manitoba S Saskatchewan T Alberta
V British Columbia X NW-Territ. Nunavut Y Yukon
Code:
def CheckCanadianPostalcodes(p, strictCapitalization=False, fixSpace=True):
'''returns a Tuple of (boolean, string):
- (True, postalCode) or
- (False, error message)
By default lower and upper case characters are allowed,
a missing middle space will be substituted.'''
pc = p.strip() # copy p, strip whitespaces front/end
if fixSpace and len(pc) == 6:
pc = pc[0:3] + " " + pc[3:] # if allowed / needed insert missing space
nums = "0123456789" # allowed numbers
alph = "ABCEGHJKLMNPRSTVWXYZ" # allowed characters (WZ handled below)
mustBeNums = [1,4,6] # index of number
mustBeAlph = [0,2,5] # index of character (WZ handled below)
illegalCharacters = [x for x in pc
if x not in (nums + alph.lower() + alph + " ")]
if strictCapitalization:
illegalCharacters = [x for x in pc
if x not in (alph + nums + " ")]
if illegalCharacters:
return(False, "Illegal characters detected: " + str(illegalCharacters))
postalCode = [x.upper() for x in pc] # copy to uppercase list
if len(postalCode) != 7: # length-validation
return (False, "Length not 7")
for idx in range(0,len(postalCode)): # loop over all indexes
ch = postalCode[idx]
if ch in nums and idx not in mustBeNums: # is is number, check index
return (False, "Format not 'ADA DAD'")
elif ch in alph and idx not in mustBeAlph: # id is character, check index
return (False, "Format not 'ADA DAD'") # alpha / digit
elif ch == " " and idx != 3: # is space in between
return (False, "Format not 'ADA DAD'")
if postalCode[0] in "WZ": # no W or Z first char
return (False, "Cant start with W or Z")
return (True,"".join(postalCode)) # yep - all good
Testing:
testCases = [(True,"A9A 9A9"), (True,"a9a 9a9"), (True,"A9A9A9"),
(True,"a9a9a9"), (False,"w9A 9A9"), (False,"z9a 9a9"),
(False,"a9a 9!9")]
for t in testCases:
pc = CheckCanadianPostalcodes(t[1]) # output differs, see func description
assert pc[0] == t[0], "Error in assertion: " + str(t) + " became " + str(pc)
print(t[1], " => ", pc)
pp = input("Postal code: ")
print(CheckCanadianPostalcodes(pp)) # output differs, see func description
Output:
A9A 9A9 => (True, 'A9A 9A9')
a9a 9a9 => (True, 'A9A 9A9')
A9A9A9 => (True, 'A9A 9A9')
a9a9a9 => (True, 'A9A 9A9')
w9A 9A9 => (False, 'Cant start with W or Z')
z9a 9a9 => (False, 'Cant start with W or Z')
a9a 9!9 => (False, "Illegal characters detected: ['!']")
Postal code: b2c3d4
(False, "Illegal characters detected: ['d']")
This answer with regex (not accepted) delivers the correct regex.
Number of possible postal codes (from wikipedia)
Postal codes do not include the letters D, F, I, O, Q or U, and the first position also does not make use of the letters W or Z.
[...]
As the
Canada Post reserves some FSAs for special functions, such as for test or promotional purposes, (e.g. the H0H 0H0 for Santa Claus, see below) as well as for sorting mail bound for destinations outside Canada.[...]
which leaves you with ABCEGHJKLMNPRSTVXY without WZ as 1st char.
Edit: Incoperated change suggestion by jl-peyret
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With