IBAN prüfen JavaScript: Mod 97, Regex und ein React-Feld

Deine Auszahlungseinstellungen, dein Lieferantenformular oder deine Rechnungsvorlage fragen nach einem Bankkonto, und die Leute fügen IBANs in jeder Form ein: kleingeschrieben, in Vierergruppen, mit Bindestrichen, mit den geschützten Leerzeichen aus einem PDF, manchmal mit „IBAN:“ davor. Viele Snippets zum Thema „IBAN prüfen JavaScript“ hören bei einem Regex auf, der eine vertippte Ziffer durchlässt, oder rufen parseInt auf und lehnen damit gültige Konten ab. In diesem Tutorial schreiben wir den Mod-97-Check in TypeScript, bauen ihn in eine zod-Regel und ein React-Feld ein, das beim Tippen formatiert, lesen die Bank aus rumänischen IBANs aus und zeigen das Ergebnis mit einem Copy-Button an. Die UI nutzt Masked Input (Pro), Input und Copy Button (beide kostenlos) aus Wingo UI, der Bibliothek, die wir bauen. Wir sind also nicht neutral. Der Validator ist reines TypeScript, das du überall einfügen kannst.
Warum reicht ein Regex nicht, um eine IBAN zu prüfen?
Ein Regex prüft die Form, und ein Tippfehler behält die Form. Wer nach „IBAN Regex“ sucht, findet meist diesen Ausdruck. Du wendest ihn an, nachdem du die Leerzeichen entfernt und alles in Großbuchstaben umgewandelt hast:
Zwei Buchstaben für das Land, zwei Prüfziffern, dann 11 bis 30 Buchstaben oder Ziffern, denn IBANs reichen von 15 Zeichen (Norwegen) bis maximal 34. Ein Länder-Pattern ist strenger: Das für Rumänien lautet ^RO\d{2}[A-Z]{4}[A-Z0-9]{16}$. Beide akzeptieren RO49AAAA1B31007593840001, also die rumänische Beispiel-IBAN aus dem IBAN-Register mit geänderter letzter Ziffer.
Genau dafür gibt es die zwei Prüfziffern. Jeder String in der rumänischen Form besteht den Regex, aber nur etwa 1 von 97 zufälligen Strings besteht mod 97: In einem Lauf mit 200.000 zufälligen Strings war es etwa 1 %. Behalte den Regex trotzdem, als ersten von drei Checks. So kann deine Meldung „das ist keine IBAN“ sagen, bevor sie „diese IBAN hat einen Tippfehler“ sagt.
Wie funktioniert der Mod-97-Check der IBAN?
Das Verfahren heißt kurz IBAN mod 97: Verschieb die ersten vier Zeichen ans Ende, ersetz jeden Buchstaben durch zwei Ziffern (A ist 10, B ist 11, bis Z mit 35), lies das Ergebnis als eine einzige Ganzzahl und teil sie durch 97. Bei einer gültigen IBAN bleibt der Rest 1. Der IBAN-Artikel auf Wikipedia (opens in a new tab) beschreibt diese Schritte aus ISO 13616. Wer die IBAN vergibt, berechnet die Prüfziffern als 98 minus den Rest derselben Zahl mit 00 an ihrer Stelle. Deshalb landet eine gültige IBAN bei 1.
Hier die britische Beispiel-IBAN, von Hand durchgerechnet:
Diese Ganzzahl hat 28 Stellen, und der JavaScript-Typ Number ist nur bis 2^53 exakt, und 2^53 hat 16 Stellen. Number(digits) % 97 und parseInt(digits, 10) % 97 liefern für diese IBAN beide 5 und lehnen damit ein gültiges Konto ab. BigInt(digits) % 97n funktioniert. Den Rest Zeichen für Zeichen weiterzutragen funktioniert auch und spart die Umwandlung in einen Ziffern-String.
Laut Wikipedia erkennt der Check jedes einzelne falsche Zeichen und alle oder fast alle Vertauschungen benachbarter Zeichen. Wir haben das getestet. Bei 2.000 zufälligen deutschen IBANs, die nach dem Ländercode nur aus Ziffern bestehen, fiel jede geänderte Ziffer und jede Vertauschung zweier Nachbarn durch den Check. Buchstaben schwächen den Check: Bei 2.000 zufälligen IBANs im rumänischen Stil mit Buchstaben im Kontoteil haben etwa 0,35 % der Änderungen eines einzelnen Zeichens und der Nachbarvertauschungen trotzdem bestanden, ungefähr 1 von 300, denn ein Buchstabe wird zu zwei Ziffern. Machst du im Registerbeispiel aus 1B ein B1, ergeben beide 111, und RO49AAAAB131007593840000 besteht.
Wie prüfe ich eine IBAN in TypeScript?
Willst du eine IBAN validieren, normalisier die Eingabe und lass dann drei Checks in dieser Reihenfolge laufen: die Form, die Länge für das Land und mod 97. Gib zurück, welcher Check gescheitert ist. Dann kann das Formular das Problem erklären, statt nur „ungültig“ zu melden:
Vier Entscheidungen aus dieser Datei solltest du übernehmen, auch wenn du den Rest neu schreibst:
- Zuerst in Großbuchstaben umwandeln.
"n".charCodeAt(0) - 55ergibt 55,"N"dagegen 23. Ohne diesen Schritt scheitert also jede kleingeschriebene IBAN. - Jede Art von Leerzeichen entfernen.
\sin einem JavaScript-Regex erfasst auch die geschützten und schmalen Leerzeichen, die PDFs und Banking-Apps zwischen die Gruppen setzen. - Länder ablehnen, in die du nicht auszahlst. Die Tabelle enthält die 42 IBAN-Ländercodes aus der Übersicht der SEPA-Teilnehmer des EPC vom August 2026 (opens in a new tab), Albanien, Moldau, Montenegro, Nordmazedonien und Serbien eingeschlossen. Alles andere bekommt
"country", die ehrliche Antwort für ein SEPA-Auszahlungsformular. Wenn du IBANs aus allen Ländern annimmst, nimm eine Bibliothek (siehe den letzten Abschnitt). - Testdaten erzeugen.
ibanCheckDigitsbaut aus jedem Land und jedem Kontoteil eine gültige IBAN. So enthalten deine Fixtures nie das Konto einer echten Person.
Wie ist die rumänische IBAN aufgebaut?
Eine rumänische IBAN hat 24 Zeichen: RO, zwei Prüfziffern, vier Buchstaben für die Bank und 16 Buchstaben oder Ziffern für Filiale und Konto. Die vier Bankbuchstaben sind die ersten vier Zeichen des BIC der Bank, also ihres SWIFT-Codes. BTRL steht demnach für Banca Transilvania (BIC BTRLRO22). Die Tabelle IBAN formats by country (opens in a new tab) auf Wikipedia notiert das Format als RO kk bbbb cccc cccc cccc cccc.
Daraus folgen zwei Regeln. Eine Regel „nach dem Bankcode nur Ziffern“ lehnt echte rumänische Konten ab, denn der Kontoteil darf Buchstaben enthalten: IBANs der Banca Transilvania zum Beispiel enthalten direkt nach dem Bankcode Buchstaben wie RONCRT. Und die Bank findest du mit einem einzigen Lookup:
Zeig den Namen als Hinweis, den die Person wiedererkennt. Er beweist nichts über das Konto, und die Tabelle ist eine Momentaufnahme von Banken, die fusionieren. Als OTP Bank Rumänien Anfang 2025 in der Banca Transilvania aufging, bekamen ihre Kunden neue BTRL-IBANs, und die Banca Transilvania schickte Arbeitgebern die neuen IBANs für Gehälter ab März 2025 (opens in a new tab). Eine alte OTP-IBAN besteht mod 97 trotzdem.
Wie baue ich ein IBAN-Feld, das beim Tippen formatiert?
Nimm ein maskiertes Feld, das den Rohwert getrennt vom angezeigten Text speichert. Das Preset iban von Masked Input wandelt beim Tippen in Großbuchstaben um, gruppiert in Vierergruppen, hält den Cursor direkt hinter dem getippten Zeichen und entfernt Trennzeichen aus eingefügtem Text. Sobald die IBAN vollständig ist, lässt es mod 97 laufen und blendet ein Häkchen oder ein Warnsymbol ein; der rote Ring und aria-invalid warten, bis du das Feld verlässt. Auf Smartphones behält es mit autoCapitalize="characters" die Texttastatur, denn ein Ziffernblock hat keine Buchstaben für den Ländercode.
$ npx wingo-ui@latest add masked-inputDas Preset bringt Längen für neun Länder mit: Rumänien, Moldau, Deutschland, Großbritannien, Frankreich, Italien, Spanien, Bulgarien und Ungarn. Für jedes andere Land gruppiert es weiterhin in Vierergruppen, wartet aber auf 34 Zeichen, bevor es prüft. Eine niederländische IBAN bekommt ihr Symbol also nie. Übergib eine Maske, die sich aus derselben Tabelle berechnet wie dein Validator. Das Preset behält dabei die Umwandlung in Großbuchstaben und seine Tastatureinstellungen:
Die zod-Regel macht aus jedem gescheiterten Check eine eigene Meldung und gibt deiner Datenbank das elektronische Format ohne Leerzeichen:
Binde sie mit Controller von React Hook Form an, denn das Input-Element hält den maskierten Text und onValueChange liefert dir den Rohwert. Mit validate={isValidIban} sind sich das Symbol im Feld und die zod-Regel bei jeder IBAN einig:
Die Beschreibung zeigt „Banca Transilvania“, sobald jemand RO17BTRL tippt. So kann die Person schnell bestätigen, dass sie das richtige Konto kopiert hat. Der onPaste-Handler deckt den einen Fall beim Einfügen ab, den die Maske nicht bereinigen kann. Das Feld verwirft jedes Trennzeichen, behält aber Buchstaben. Ein aus einem Kontoauszug kopiertes „IBAN: RO17 BTRL ...“ würde also zu IB17 BTRL ... werden und mit der Länder-Meldung scheitern. Der Handler entfernt das Label mit electronicIban, bevor die Maske den Text sieht.
Wenn du die Regel nicht selbst schreiben willst: Die Pro-Lib form-validation hat createValidators().iban(), mit einer einzigen Meldung für jeden Fehler und ohne Länderbeschränkung.
Wie zeige ich eine IBAN so an, dass man sie kopieren kann?
Zeig sie in Vierergruppen an und kopier sie ohne Leerzeichen. Die Gruppen helfen beim Vorlesen oder beim Abgleich mit einer Papierrechnung. In die Zwischenablage gehört das elektronische Format, denn eine IBAN mit 34 Zeichen wächst mit Leerzeichen auf 42 Zeichen, und ein Bankformular mit maxLength={34} schneidet beim Einfügen das Ende ab.
Copy Button rendert einen Icon-Button mit dem Label „IBAN kopieren“. Auf dem Desktop wechselt sein Tooltip zu „Copied“; auf dem Smartphone geben das Häkchen, eine kurze Vibration und eine Ansage für Screenreader das Feedback, und die kleine Größe behält auf Touch-Geräten eine Trefferfläche von 44px. Die gruppierte IBAN bricht an ihren Leerzeichen um und schiebt die Zeile so nie über die Breite eines 360px-Bildschirms hinaus.
Heißt eine gültige IBAN, dass das Konto existiert?
Nein. Die Prüfziffern beweisen, dass die IBAN korrekt aufgebaut ist. Ein geschlossenes Konto, ein Konto bei einer inzwischen fusionierten Bank und das Konto der falschen Person bestehen den Check alle. Den letzten Fall fängt der Name des Kontoinhabers ab. Nach der EU-Verordnung über Sofortzahlungen müssen Banken die Empfängerüberprüfung (Verification of Payee) anbieten. Sie vergleicht vor einer Überweisung den Namen des Empfängers mit dem Konto und liefert ein Ergebnis wie Übereinstimmung, teilweise Übereinstimmung oder keine Übereinstimmung. Die Übersicht der EZB zur Verordnung (opens in a new tab) nennt den 9. Oktober 2025 für den Euroraum und den 9. Juli 2027 für die Mitgliedstaaten ohne Euro, Rumänien eingeschlossen.
Dieser Check läuft bei der Bank des Zahlers, wenn das Geld abgeht, lange nachdem dein Formular abgeschickt wurde. Prüf also die Ziffern, während die Leute tippen, und frag neben der IBAN nach dem Namen des Kontoinhabers, wie es das Formular oben tut. Dann hat die Bank einen Namen zum Vergleichen.
Sollte ich stattdessen eine Bibliothek wie ibantools nehmen?
Nimm eine, wenn du IBANs aus allen Ländern annimmst. Stand Oktober 2026 bringt ibantools (opens in a new tab) 4.5.4 (veröffentlicht im April 2026, MIT oder MPL-2.0) die Länge und das Kontomuster jedes Registerlandes mit, validateIBAN liefert Fehlercodes, die du auf Meldungen abbilden kannst, und isValidBIC prüft SWIFT-Codes. Es prüft auch die nationalen Prüfziffern, die manche Länder im Kontoteil ergänzen, etwa Belgien, Spanien und Frankreich. Die Datei oben lässt diese aus. Ein Haken für ein SEPA-Formular: isSEPACountry liefert in 4.5.4 für Albanien, Moldau, Montenegro, Nordmazedonien und Serbien noch false. Das Paket iban (opens in a new tab), die andere übliche Antwort, wurde zuletzt im Februar 2020 veröffentlicht. Für ein reines SEPA-Formular deckt die Datei oben Form, Länge und mod 97 ohne Abhängigkeit ab, und du kannst jede Zeile davon lesen.
Sollte ich diesen Code kopieren oder installieren?
Kopier ihn, wenn du ein einziges einfaches Feld brauchst: lib/iban.ts, die zod-Regel und der kostenlose Input reichen dafür. In Wingo UI Pro ist Masked Input das Feld aus der Demo, und die Lib invoicing exportiert isValidIban (Längen für 19 Länder, jedes andere Land bekommt Form und mod 97), formatIban, getIbanBank und eine Tabelle RO_BANKS mit 19 rumänischen Bankcodes, neben den Checks aus unserem Guide zur rumänischen CUI-Validierung und unserem rumänischen CNP-Validator. Die Pläne findest du auf der Preisseite. Installier das Feld und den kostenlosen Copy-Button mit npx wingo-ui@latest add masked-input copy-button. Für den Rest der Formular-Anatomie lies React Form Components: barrierefreie Felder, zod und Mobile oder stöber in weiteren Komponenten-Guides.
Häufige Fragen
Wie prüfe ich eine IBAN in JavaScript?
Entferne Leerzeichen und Bindestriche, wandle den String in Großbuchstaben um und prüf die Länge für das Land. Dann verschiebst du die ersten vier Zeichen ans Ende, ersetzt jeden Buchstaben durch seine Zahl (A ist 10, Z ist 35) und berechnest den Rest mod 97 Ziffer für Ziffer; die IBAN ist gültig, wenn der Rest 1 ist.
Wie sieht der Regex für eine IBAN aus?
Nachdem du die Leerzeichen entfernt und alles in Großbuchstaben umgewandelt hast, passt /^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/ auf die Form jeder IBAN, und ein Länder-Pattern wie ^RO\d{2}[A-Z]{4}[A-Z0-9]{16}$ prüft zusätzlich die Länge. Keiner von beiden testet die Prüfziffern, also lass nach dem Regex noch mod 97 laufen.
Wie viele Zeichen hat eine rumänische IBAN?
24: RO, zwei Prüfziffern, vier Buchstaben für die Bank (die ersten vier Zeichen ihres BIC) und 16 Buchstaben oder Ziffern für Filiale und Konto, zum Beispiel RO49 AAAA 1B31 0075 9384 0000.
Heißt eine gültige IBAN, dass das Konto existiert?
Nein. Die Prüfziffern beweisen nur, dass die IBAN korrekt aufgebaut ist, also besteht auch ein geschlossenes Konto oder das Konto der falschen Person den Test. In der EU vergleicht die Empfängerüberprüfung (Verification of Payee) bei der Bank des Zahlers den Namen des Empfängers mit dem Konto, bevor eine Überweisung ausgeführt wird, ab dem 9. Oktober 2025 im Euroraum und ab dem 9. Juli 2027 in Rumänien und den anderen Mitgliedstaaten ohne Euro.
Warum lehnt mein IBAN-Check gültige IBANs ab?
Oft liegt es an Number oder parseInt: Die umgestellte IBAN hat mehr Ziffern, als der Typ Number in JavaScript exakt darstellen kann, also kommt ein falscher Rest heraus. Kleinbuchstaben, aus einem PDF eingefügte geschützte Leerzeichen und ein vorangestelltes „IBAN:“ sind die anderen üblichen Verdächtigen.
Wie finde ich die Bank zu einer rumänischen IBAN?
Lies die Zeichen 5 bis 8. Sie sind die ersten vier Zeichen des BIC der Bank, also steht BTRL für Banca Transilvania und RNCB für BCR. Halte deine Tabelle aktuell, denn fusionierte Banken hinterlassen alte Codes.
- IBAN
- Formularvalidierung
- TypeScript
- React
- Rumänien
- Zahlungen


