IBAN Prüfziffer validiert

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Marceline
User
Beiträge: 20
Registriert: Freitag 2. November 2018, 16:35

Grüßt euch!
Ich soll bis morgen ein Programm schreiben, welches die iBan-Prüfziffern der Länder Deutschland, Schweiz und Frankreich validiert.
Im Internet habe ich einige Lösungen gefunden, aber die alle viel zu kompliziert. Wir haben jetzt erst angefangen, unser Thema in der Vorlesung heute waren ,,while- und for-Schleifen''.

Meine Idee wäre, zuerst einmal eine elif-Verzweigung für die unterschiedlichen Länder und deren IBANs einzurichten, (Laut meiner Recherche im Netz: Deutschland: 22 Zeichen, davon 1. und 2. Zeile ,,DE‘‘, danach zwei Ziffern, dann 8 Zeilen Bankleitzahl, dann 10 Zeilen Kontonummer.
Schweiz: 21 Zeichen, davon 1. Und 2. Zeile ,,CH‘‘, danach zwei Ziffern, dann 6 Zeilen BLZ und und 11 Zeilen Kontonummer
Frankreich: 27 Zeichen, davon 1. Und 2. Zeile ,,FR‘‘, danach 5 Zeilen BLZ, 5 Zeilen Bankbereich, 11 Zeilenkontonummer und wieder zwei Ziffern

Die Prüfung der deutschen IBAN erfolgt, indem ihre ersten vier Stellen ans Ende verschoben und die Buchstaben wieder durch 1314 ersetzt werden. Diese Zahl Modulo 97 muss 1 ergeben. Dann ist die IBAN gültig.

Wie schaff ich es, die ersten vier Zeilen in die hinteren zu verschieben ? Mit append.? Das Thema Listen hatten wir noch nicht.

Mir ist klar, dass ich D den Wert 13 und E den Wert 14 zuornden muss. Aber das ist noch keine Liste.

Wäre für einen Hinweis dankbar. Entschuldigt die simple Baby-Frage, aber mir läuft nach zweitätiger Recherche in zahlreichen Internetforen die Zeit davon.
Benutzeravatar
Marceline
User
Beiträge: 20
Registriert: Freitag 2. November 2018, 16:35

Mein Versuch:

# IBAN-Nummer = DE08700901001234567890

# Wert der Buchstaben zu den Zahlen um jeweils 9 erhöhen
D = 13
E = 14
F = 15
R = 28
C = 12
H = 17

liste = ibannummer = input ('Geben Sie ihre iBan Nummer ein)
if 'DE' in ibannummer :
bankleitzahl = ibannummer[5,6,7,8,9,10,11] #bankleitzahl 70090100
kontonummer = ibannummer[12:] #kontonummer 1234567890
pruefsumme = bankleitzahl + kontonummer.append(ibannummer[0,1,2,3])
if pruefsumme % 97 = 1 :
print ('validierte IBAN')
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Marceline: Das ist ja nicht einmal syntaktisch korrektes Python. Ein bisschen mehr Mühe musst Du Dir schon geben. Und einfach irgendwie etwas zusammen raten funktioniert nicht. Du musst schon eine Vorstellung davon haben was Dein Code tut.

Also erst einmal musst Du wissen was Du machen musst. Und das musst Du dann Schritt für Schritt in Code ausdrücken. Dabei musst Du wissen was der jeweilige Code machen soll und was er tatsächlich macht. Das kannst Du zum Beispiel über `print()`-Ausgaben überprüfen. Und wenn die Ausgabe dann nicht mit dem übereinstimmt was Du ja sicher irgendwo mit Papier und Stift mal an Beispielen durchprobiert hast, dann ist der Code an der Stelle falsch. *Dann* kannst Du mit dem konkreten Problem und lauffähigem Code hier fragen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Marceline
User
Beiträge: 20
Registriert: Freitag 2. November 2018, 16:35

Ok, ich habe es jetzt für Deutschland hinekriegt. Jetzt muss ich es noch für Schweizerische und Französische IBANs machen. Das Problem ist, dass dort, im Gegensatz zu Deutschland, auch Buchstaben in der Kontonummer enthalten sind. Ich will es jetzt so machen, dass z.B. A immer den Wert 10 hat, B immer 11, C = 12, D = 13...., Z = 35. Arbeitet man dann mit def oder mit einer Liste?

Code: Alles auswählen

if 'CH' in ibannummer:   #wennn IBAN Nummer Schweizerisch
    #Beispiel Schweiz: CH100023000A109822346
    bankleitzahl = ibannummer  [4:9] #Bankleitzahl 00230
    kontonummer = ibannummer[9:] #00A109822346
    #das A durch 10 ersetzen
    def A():
        A = 10
    print (kontonummer)
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Lies dir doch diese Beschreibung der Validierung noch mal durch.
https://de.wikipedia.org/wiki/Internati ... ontonummer
Validierung
Im Rahmen von IPI und ECBS wurde das Prüfziffernverfahren auf den Standard ISO 7064 mod 97-10 festgelegt und von den nationalen Normungsgremien der Banken übernommen.[26] Die Prüfsumme liegt im Bereich „02“ bis „98“, durch abweichende Berechnungsmethoden bei verschiedenen Finanzinstituten kamen aber auch „00“, „01“ und „99“ vor. Die Korrekturen sind weitgehend abgeschlossen. Jedoch kann nicht ausgeschlossen werden, dass weiterhin IBANs mit „falschen“ Prüfziffern existieren.

Zur Validierung der Prüfsumme wird zunächst eine Zahl erstellt:
Diese setzt sich aus BBAN (in Deutschland z. B. 18 Stellen) + Länderkürzel kodiert + Prüfsumme zusammen. Dabei werden die beiden Buchstaben des Länderkürzels sowie weitere etwa in der Kontonummer enthaltene Buchstaben durch ihre Position im lateinischen Alphabet + 9 ersetzt (A = 10, B = 11, …, Z = 35).
Nun wird der Rest berechnet, der sich beim ganzzahligen Teilen der Zahl durch 97 ergibt (Modulo 97).
Das Ergebnis muss 1 sein, ansonsten ist die IBAN falsch.
Beispiel:

1 IBAN DE68 2105 0170 0012 3456 78
2 Umstellung 2105 0170 0012 3456 78DE 68
3 Modulo 210501700012345678131468 mod 97 = 1
Die Umwandlung der IBAN kann durch einfache Stringoperationen erfolgen, das Ergebnis in eine Ganzzahl umwandeln und dann Modulus 97 berechnen.
Dafür brauch man keine Listen, Schleifen etc.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

Strings haben in Python eine "startswith()' Methode. Damit lässt sich dein Problem lösen, ohne das du irgendwelche komischen Substitutionen machen musst.

Plan B: du weißt, dass der IBAN immer mit der 2-stelligen Länderkennung, beginnt. Slicing kennst du auch, verwendest du ja im zuletzt gezeigten Code. Also kannst du auch die ersten beiden Stellen aus dem IBAN extrahieren und dann den Vergleich gegen DE, FR, CH, ... machen.

Gruß, noisefloor
Benutzeravatar
Marceline
User
Beiträge: 20
Registriert: Freitag 2. November 2018, 16:35

Danke für die Antwort. Vielleicht zeig ich der Vollständigkeit halber meinen ganzen Code.

Code: Alles auswählen

#Beispiel-IBAN Nummer: DE08700901001234567890
ibannummer = input ('Geben Sie ihre iBan Nummer ein: ')
if 'DE' in ibannummer:   #wennn IBAN Nummer deutsch
    bankleitzahl = ibannummer  [4:12] #Bankleitzahl 70090100
    kontonummer = ibannummer[12:] #Kontonummer 1234567890
    bban = bankleitzahl + kontonummer #BBAN 700901001234567890
    landererkennung = '1314' 
    landererkennung_ergaenzt= '131400' #Ländererkennung mit 00 ergänzt
    pruefungssumme = bban + landererkennung_ergaenzt #Prüfsumme 
    pruefungssumme_modulo = int(pruefungssumme) % 97 #Prüfsumme Modulo 97
    pruefungsziffer = 98 - pruefungssumme_modulo
    if pruefungsziffer > 9:
        pruefungsziffer = 98 - pruefungssumme_modulo
    else:                       
        pruefungsziffer = 98 - pruefungssumme_modulo
        pruefungsziffer = str(pruefungsziffer).zfill(2)
        #wenn (98 - Prüfungssumme) < 9 füge ergänze eine führende Null (08)
    print ('Ihre Pruefziffer lautet', pruefungsziffer)
    #Prüfungsziffer rausgeben
    pruefung = bban + landererkennung + pruefungsziffer
    if int(pruefung) % 97 == 1 :  #Validieren
        print ('Sie haben eine gültige deutsche IBAN-Nummer')
        
elif 'CH' in ibannummer:   #wennn IBAN Nummer Schweizerisch
    #Beispiel Schweiz: CH100023000A109822346
    bankleitzahl = ibannummer  [4:9] #Bankleitzahl 00230
    kontonummer = ibannummer[9:] #00A109822346
    bban = bankleitzahl + kontonummer #BBAN
    landererkennung = '1217' 
    landererkennung_ergaenzt= '121700' #Ländererkennung mit 00 ergänzt
    pruefungssumme = bban + landererkennung_ergaenzt #Prüfsumme
    print (pruefungssumme)
    pruefungssumme_modulo = int(pruefungssumme) % 97 #Prüfsumme Modulo 97
Wie gesagt, für Deutschland funktioniert es einwandfrei. Bei schweizerischen und französischen IBANS stoße ich auf das Problem, dass der Interpreter merkt, weil in der letzten Zeile beim Integer für die Prüfungssumme einen Buchstaben (in meinem Beispiel das ,A') enthält und denn will ich halt raus kriegen, bzw. in A = 10 umwandeln.

startswith() hab ich probiert, kommt aber nur unsinn raus. Ist die IBAN-Nr. überhaupt ein String? Es gibt mir wirklich nur darum, die Buchstaben A = 10, B = 11,...Z = 35 zuzuordnen? Auch mit ''=='' und ''is'' komme ich leider nicht weiter :(
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
startswith() hab ich probiert, kommt aber nur unsinn raus.
Dann zeig' mal, was du gemacht hast. Das wird nämlich funktionieren, wenn man es korrekt angeht :-)
Ist die IBAN-Nr. überhaupt ein String?
Alles, was du über `input` einliest, ist erst mal ein String in Python.

Gruß, noisefloor
Benutzeravatar
Marceline
User
Beiträge: 20
Registriert: Freitag 2. November 2018, 16:35

Verstehe gerade nicht die Funktion von startswith. (Das hatten wir noch nicht). Man dann damit überprüfen, mit welcher Länderkennzeichnung die IBAN startet, z.b.

ibannummer.startswith('CH')
print ('True')

,aber hilft mir das weiter, die Zahlen umzuschreiben?

Code: Alles auswählen

dict = {'a':'10','b':'11','c':'12','d':'13','e':'14','f':'15','g':'16','h':'17',
    'i':'18','j':'19','k':'20','l':'21','m':'22','n':'23','o':'24','p':'25','q':'26',
    'r':'27','s':'28','t':'29','u':'30','v':'31','w':'32','x':'33','y':'34','z':'35'
    }
    print (kontonummer)
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Marceline: Ich verstehe ja nicht warum Du für verschiedene Länder verschiedene Prüfungen machen willst. Das *erstellen* von IBANs aus Kontonummer und Bankleitzahl ist länderspezifisch, die Prüfung sollte allgemein möglich sein. Dein Code macht da auch viel zu viel, weil man zum prüfen gar nicht wissen muss wie sich die IBAN auf Kontonummer und Bankleitzahl aufteilt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Marceline: das Umwandeln von Buchstaben in Zahlen geht z.B. mit »int('F', 36)«. Dann geht die Prüfung auch in eine, zwei Zeilen. Dein IBAN-Beispiel für die Schweiz ist falsch.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Er muss die Buchstaben nicht in Zahlen umwandeln, sondern in Strings

Code: Alles auswählen

IBAN = 'DE68210501700012345678'
ersetzt = IBAN.replace('DE', '1314')
if int(f'{ersetzt[6:]}{ersetzt[:6]}') % 97 == 1:
    print('IBAN korrekt')
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Marceline hat geschrieben: Freitag 2. November 2018, 22:45 Verstehe gerade nicht die Funktion von startswith. (Das hatten wir noch nicht). Man dann damit überprüfen, mit welcher Länderkennzeichnung die IBAN startet, z.b.

ibannummer.startswith('CH')
print ('True')
Die `startswith()` Methode hat einen Rückgabewert, nämlich `True` oder `False`, damit musst du arbeiten. In deinem Beispiel wertest du den Rückgabewert nicht aus, von daher wird `print('True'') immer ausgegeben. Beispiel für `startswith`:

Code: Alles auswählen

>>> iban = 'DE08700901001234567890'
>>> if iban.startswith('CH'):
...     print('Schweizer IBAN')
... elif iban.startswith('DE'):
...     print('Deutscher IBAN')
... else:
...     print('Weder deutscher noch schweizer IBAN')
... 
Deutscher IBAN
>>>
Gruß, noisefloor
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@ThomasL: da beliebige Buchstaben an beliebigen Stellen vorkommen können, ist das zu einfach gedacht.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Sirius3 hat geschrieben: Samstag 3. November 2018, 15:47 @ThomasL: da beliebige Buchstaben an beliebigen Stellen vorkommen können, ist das zu einfach gedacht.
ok, dann habe ich für dich mal weitergedacht und der TS freut sich

Code: Alles auswählen

tabelle = {}
for zahl in range(10):
    tabelle[str(zahl)] = str(zahl)
for letter in range(65, 91):
    tabelle[chr(letter)] = str(letter-55)

IBANS = ('DE68210501700012345678', 'AT611904300234573201', 'CH78005540A1024502601')
for iban in IBANS:
    ersetzt = ''
    for zeichen in iban:
        ersetzt = f'{ersetzt}{tabelle[zeichen]}'
    if int(f'{ersetzt[6:]}{ersetzt[:6]}') % 97 == 1:
        print('IBAN korrekt')
IBAN korrekt
IBAN korrekt
IBAN korrekt
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich habe das spasseshalber mal in Vala gelöst:

Code: Alles auswählen

using GLib;
using Gmp;

static int main (string[] args)
{
    if (args.length == 1) {
        stdout.puts ("Usage: check_iban IBAN\n");
        return 1;
    }

    string iban = args[1];
    if (! iban.is_ascii ()) {
        stdout.puts ("IBAN must be ASCII only.\n");
        return 2;
    }
    if (iban.length < 4) {
        stdout.puts ("IBAN is too short.\n");
        return 2;
    }
    
    string rearranged = iban.substring (4).concat (iban.substring (0, 4));
    StringBuilder characters_replaced_by_digits =
            new StringBuilder.sized (iban.length + 2);
    for (int i = 0; i < rearranged.length; ++i) {
        char c = rearranged[i];
        if (c.isalpha ()) {
            characters_replaced_by_digits
                .append (((uint8) (c.toupper () - 'A' + 10)).to_string ());
        } else if (c.isdigit ()) {
            characters_replaced_by_digits.append_c (c);
        } else {
            stdout.printf ("Unexpected character '%c' in IBAN.\n", c);
            return 2;
        }
    }
    
    Integer number = 
            Integer.init_set_str (characters_replaced_by_digits.str, 10);
    bool is_valid = Integer.fdiv_ui (number, 97) == 1;
    stdout.printf ("The IBAN %s is %s.\n",
            iban, (is_valid) ? "valid" : "invalid");
    return (is_valid) ? 0 : 3;
}
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@ThomasL: das iterative Stringzusammensetzen ist ja noch schlimmer als das übliche `ersetzt += tabelle[zeichen]`, denn da hat der Interpreter wirklich keine Chance mehr, das zu optimieren.

Da Du schon eine Lösung gepostet hast, hier die zwei-Zeilen-Lösung:

Code: Alles auswählen

IBANS = ['DE68210501700012345678', 'AT611904300234573201', 'CH78005540A1024502601']
for iban in IBANS:
    ersetzt = ''.join(str(int(c, 36)) for c in iban[4:] + iban[:4])
    print('{} {}korrekt'.format(iban,
        "" if int(ersetzt) % 97 == 1 else "nicht "))
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Sirius3 hat geschrieben: Samstag 3. November 2018, 18:21 @ThomasL: das iterative Stringzusammensetzen ist ja noch schlimmer als das übliche `ersetzt += tabelle[zeichen]`
Schmunzel, und da dachte ich mir doch glatt das wäre besonders elegant :lol:
Aber ich bin jederzeit bereit zu lernen und jetzt habe ich für solche Fälle ein neues Snippet in meiner Sammlung. Danke :!:
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Antworten