2017-12-13 5 views
3

Ich versuche, ein Programm zu machen, das eine Postleitzahleingabe vom Benutzer nimmt und prüft, ob es gültig ist. Bisher habe ich:Kann nicht herausfinden, wie Ausdrücke verwendet werden, um eine kanadische Postleitzahl in Python zu validieren

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.") 

Der Code fein läuft, aber ich weiß Ausdrücke wäre viel mehr lebensfähig, aber ich habe nicht herausfinden konnte, wie sie funktionieren.

Das kanadische Postleitzahl-Format ist: L/N/LN/L/N

Dank

+0

Sie meinen mit regulären Ausdrücken, denke ich? 'import re len (re.findall (pattern, string_to_search))' machen Sie das Muster für die Postleitzahl dann sehen, ob 'Len' größer als 1 sollte funktionieren. –

+0

https://stackoverflow.com/questions/15774555/efficient-regex-for-canadian-postalcode-function –

+0

KEIN Duplikat von [kanadisch-postal-code-validation-python-rege] (https: // stackoverflow.com/questions/29906947/canadian-postal-code-validation-python-regex) noch [JS: efficient-regex-für-kanadische-postal-code-funktion] (https://stackoverflow.com/questions/15774555/efficient-regex-für-kanadische-postal-code-funktion). Die zweite ist Javascript und verwendet verbotene Zeichen, die erste ist keine akzeptierte Antwort (aber eine gültige Regex-Lösung) –

Antwort

3

No regex Lösung:

Ihre Fakten Holen gerade - az ist falsch, einige Buchstaben sind Ähnlichkeit weggelassen wegen:

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 and needd insert missing space 

    nums = ""    # 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 ofer all indexes 
     ch = postalCode[idx] 
     if ch in nums and idx not in mustBeNums: # is s number, check index 
      return (False, "Format not 'ADA DAD'")  
     elif ch in alph and idx not in mustBeAlph: # id s 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 


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 

Ausgang:

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']") 
Press any key to continue . . . 

Diese answer with regex (nicht akzeptiert) liefert die richtige regex.

Anzahl möglicher Postleitzahlen (from wikipedia)

Postleitzahlen umfassen nicht die Buchstaben D, F, I, O, Q oder U, und die erste Position auch nicht die Verwendung der machen Buchstaben W oder Z. [...]As the Canada Post reserviert einige FSAs für spezielle Funktionen, zB für Test- oder Werbezwecke (zB die H0H 0H0 für Santa Claus, siehe unten) sowie für die Sortierung von Postsendungen für Ziele außerhalb Kanada. [...]

, was Sie mit ABCEGHJKLMNPRSTVXY ohne WZ als 1. char.


Edit: Incoperated Änderung Vorschlag von jl-peyret

  • erlaubt fehlenden Raum
  • und klarer machen, wenn Groß-/Klein ok
  • ist
+1

Sehr schön. +1. 2 Anmerkungen: Es ist nicht offensichtlich, dass Sie Kleinbuchstaben akzeptieren und ich denke, es wäre auch schön, ADADAD ohne den Platz zuzulassen. In beiden Fällen müssten sie irgendwann wieder in ADA DAD konvertiert werden, aber es ist sinnvoll, Benutzereingaben nicht aufgrund von Groß- und Kleinschreibung oder fehlendem, aber völlig nachvollziehbarem Speicherplatz abzulehnen. –

+0

@JLPeyret danke für den Vorschlag, den Code angepasst, um Standard mit oberen/unteren und fehlenden Leerzeichen zu arbeiten. Beide sind im Ergebnis fixiert.Sie sind ein kanadischer Staatsbürger, also ist Ihr Wunsch diesbezüglich mein Befehl;) –

1

Auf der Grundlage Ihrer Frage könnten Sie:

import re 

postalCode = input("Postal code: ") 


pattern = re.match(r'[A-Z]{1}[0-9]{1}[A-Z]{1}\s[0-9]{1}[A-Z]{1}[0-9]{1}',postalCode) 

wenn Muster:

print('Valid postal code') 

anderes:

print('Invalid postal code') 

Sie auch die Unter Methode verwenden, und die Reihenfolge, so dass Sie den Code nicht wiederholen müssen, wie ich oben tat.

+0

Die Regex ist richtig basierend auf den Informationen in der Frage - leider sind nicht alle AZ erlaubt Sie verwenden die falsche Regex für die Validierung - Ihre Regex ist nicht case- unempfindlich, der Code in der Frage ist case insensitive –

1

Ich begann mit dem Konstruieren von zwei Strings, einer, der die alphabetischen Zeichen enthält, die an jeder (legalen) Position in einer Postleitzahl verwendet werden können, und einer Zeichenfolge, die die alphabetischen Zeichen enthält, die für die erste Position verwendet werden müssen.

>>> any_position = 'ABCEGHJKLMNPRSTVWXYZ' 
>>> first_position = 'ABCEGHJKLMNPRSTVXY' 

Diese paar Zeilen Code zeigen den regulären Ausdruck und seine Leistung gegen einige Testbeispiele. Wenn <_sre.SRE_Match object; ... nicht unter einem Aufruf der Regex angezeigt wird, bedeutet dies, dass der Test aus dem einen oder anderen Grund fehlgeschlagen ist.


Edit: Ich hätte erklären sollen, was die Regex tut.

  • Das Caret ('^') Zeichen am Anfang besteht darauf, darauf zu bestehen, dass die Übereinstimmung mit dem ersten Zeichen in der Betreff-Zeichenfolge beginnt. Ebenso besteht der Dollar ('$') darauf, dass die Übereinstimmung mit dem letzten Zeichen in der Betreffzeile (dh der Postleitzahl) endet.
  • [ABCEGHJKLMNPRSTVXY] 'akzeptiert' jedes einzelne Zeichen innerhalb dieses Zeichensatzes.
  • [0-9] 'akzeptiert' jedes einzelne Zeichen innerhalb dieser Zeichengruppe.
  • Das Leerzeichen "akzeptiert" ein Leerzeichen.
  • Und so weiter. Zusammengenommen bilden diese Spezifikationen eine einzige kanadische Postleitzahl, in Großbuchstaben.
  • Postleitzahlen, die alphabetische Kleinbuchstaben enthalten, sind akzeptabel, wenn Sie die Konvertierung von Kleinbuchstaben in Großbuchstaben vornehmen können. Wenn Sie diese akzeptieren möchten, fügen Sie, wie Patrick Artner vorschlägt, re.I oder re.IGNORECASE als Parameter zur match-Anweisung hinzu.


    >>> import re 
    >>> postal_code_re = re.compile(r'^[ABCEGHJKLMNPRSTVXY][0-9][ABCEGHJKLMNPRSTVWXYZ] [0-9][ABCEGHJKLMNPRSTVWXYZ][0-9]$') 
    >>> postal_code_re.match('H0H 0H0') 
    <_sre.SRE_Match object; span=(0, 7), match='H0H 0H0'> 
    >>> postal_code_re.match('A0A 0A0') 
    <_sre.SRE_Match object; span=(0, 7), match='A0A 0A0'> 
    >>> postal_code_re.match('W0A 0A0') 
    >>> postal_code_re.match('Q0A 0A0') 
    >>> postal_code_re.match('H0H 0Q0') 
    

    Es könnte wichtig sein, dass dieser Ansatz Tests das Format eines Code nur zu erwähnen. Es genügt nicht, seine Gültigkeit zu testen, da viele, viele Codes nicht verwendet werden. Für Tests mit kleinen Volumina könnte man überprüfen, ob ein Code tatsächlich verwendet wird oder ob er sich in einem gültigen Format befindet, indem man eines der Tools unter https://www.canadapost.ca/web/en/pages/tools/default.page mit Web-Scraping-Techniken verwendet.

    +0

    die Kürze der Regex-Lösung macht mir ein bisschen lang :) +1 - aber ich werde zumindest einige Fehlerhinweise ausgeben. –

    +0

    die Frage verwendet insensitive obwohl - Sie könnten die re.flag für das –

    +1

    @PatrickArtner hinzufügen: Nun schaue ich zurück auf die Frage, ich denke, der Hauptfehler in meiner Antwort ist, dass ich nicht erklärt, wie diese Regex funktioniert, die ist Worüber dieser OP unsicher war. Wie oft passiert es hier auf SO, wer weiß, was die SO mit den Ergebnissen beabsichtigt, die wir anbieten? –

    Verwandte Themen