For my project I need to extract bank data (especially BIC or BLZ, account number) from IBAN and create IBAN from account information. Has anyone done something like this alreade?
Ask claude
The Deutsche Bundesbank has a long PDF with all rules how to create an IBAN from BLZ and BIC, it depends on the bank which of those many rules applies…
Well, I have that in my FileMaker plugin, but not in the Xojo one.
I could bring it over.
Formatting or IBANs, validation and checksum calculation.
Would be nice to have, especialy validation and checksum calculation….
quite simple in fact.
Public Function VerifyIBAN(anIBAN as String) As Boolean
' nouvelle méthode 2024
' Supprimer les espaces de l'IBAN
anIBAN = anIBAN.ReplaceAll(" ", "")
' Vérifier si la longueur de l'IBAN est valide (doit être de 27 caractères pour les IBAN standard européens)
If anIBAN.Length <> 27 Then
Return False
End If
' Vérifier si l'IBAN commence par le code pays
Dim countryCode As String = anIBAN.Left(2)
If Not VerifierPaysIBAN(countryCode) Then
Return False
End If
' Déplacer les 4 premiers caractères à la fin
anIBAN = anIBAN.Mid(5)// + anIBAN.Left(4)
' Convertir les lettres en nombres
Dim convertedIBAN As String = ""
For i As Integer = 1 To anIBAN.Length
Dim ch As String = anIBAN.Mid(i, 1)
If ch >= "A" And ch <= "Z" Then
Dim newChar As String
Select Case ch
Case "A","J"
newChar = "1"
Case "B","K","S"
newChar = "2"
Case "C","L","T"
newChar = "3"
Case "D","M","U"
newChar = "4"
Case "E","N","V"
newChar = "5"
Case "F","O","W"
newChar = "6"
Case "G","P","X"
newChar = "7"
Case "H","Q","Y"
newChar = "8"
Case "I","R","Z"
newChar = "9"
End Select
convertedIBAN = convertedIBAN + newChar
Else
convertedIBAN = convertedIBAN + ch
End If
Next
Dim codeBanque As Integer = convertedIBAN.Middle(0,5).ToInteger
Dim codeGuichet As Integer = convertedIBAN.Middle(5,5).ToInteger
Dim noCompte As Integer = convertedIBAN.Middle(10,11).ToInteger
Dim cleRib As Integer = convertedIBAN.Middle(21,2).ToInteger
Dim k As Integer = (89*codeBanque)+(15*codeGuichet)+(3*noCompte)
k = k Mod 97
k = 97 - k
Return (cleRib = k)
End Function
and
Public Function VerifierPaysIBAN(iban As String) As Boolean
' Liste des codes de pays reconnus selon la norme ISO 3166-1 alpha-2
Dim paysConnus() As String = Array ("AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", _
"AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", _
"BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", _
"BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", _
"CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", _
"CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", _
"DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", _
"FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", _
"GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", _
"GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", _
"ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", _
"JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", _
"KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", _
"LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", _
"MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", _
"MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", _
"NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", _
"NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", _
"PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", _
"RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", _
"SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", _
"SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", _
"TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", _
"UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", _
"VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW")
' Extraire les deux premières lettres de l'IBAN
Dim countryCode As String = iban.Left(2)
' Vérifier si le code de pays est dans la liste des pays connus
For Each pays As String In paysConnus
If countryCode = pays Then
Return True
End If
Next
' Si le code de pays n'est pas dans la liste des pays connus
Return False
End Function
Long live Claude. ![]()
not claude …
I started it “manually”, then made it “beautify” by claude.
especially to list all the countries strings…
![]()
Since this thread gave me an idea that I can use in one of our company apps, I expanded it a bit this morning using Claude.ai.
The previous version was hard-coded for French IBANs. The current version is suitable for many countries. However, it doesn’t return a true/false result after verification, but rather the bank code, BIC, account number, and the bank’s identifier (name). This requires a mySQL database table with the corresponding information (which I can’t provide here).
Public Function VerifyIBAN(anIBAN As String) As String()
// Remove all spaces and convert to uppercase for normalization
anIBAN = anIBAN.ReplaceAll(" ", "").Uppercase
// Validate country code against known ISO 3166-1 alpha-2 codes
If Not VerifyIBANCountry(anIBAN.Left(2)) Then
Return Nil
End If
// Validate IBAN length based on country-specific rules
If Not IsValidIBANLength(anIBAN) Then
Return Nil
End If
// Rearrange: move first 4 characters to the end (IBAN standard)
Dim rearranged As String = anIBAN.Middle(4) + anIBAN.Left(4)
// Convert letters to digits: A=10, B=11, ..., Z=35
Dim numeric As String = ""
For i As Integer = 0 To rearranged.Length - 1
Dim ch As String = rearranged.Middle(i, 1)
If ch >= "A" And ch <= "Z" Then
numeric = numeric + Str(Asc(ch) - 55)
Else
numeric = numeric + ch
End If
Next
// Perform MOD-97 iteratively to avoid integer overflow on long numeric strings
Dim remainder As Integer = 0
For i As Integer = 0 To numeric.Length - 1
remainder = (remainder * 10 + numeric.Middle(i, 1).ToInteger) Mod 97
Next
If remainder <> 1 Then
Return Nil
End If
// Extract bank code and account number based on country code
Dim countryCode As String = anIBAN.Left(2)
Dim bankCode As String = ""
Dim accountNumber As String = ""
Select Case countryCode
Case "DE"
// German IBAN: positions 4-11 = bank code (BLZ), 12-21 = account number
bankCode = anIBAN.Middle(4, 8)
accountNumber = anIBAN.Middle(12, 10)
Case "AT"
// Austrian IBAN: positions 4-8 = bank code, 9-19 = account number
bankCode = anIBAN.Middle(4, 5)
accountNumber = anIBAN.Middle(9, 11)
Case "CH"
// Swiss IBAN: positions 4-8 = bank code, 9-20 = account number
bankCode = anIBAN.Middle(4, 5)
accountNumber = anIBAN.Middle(9, 12)
Case "FR"
// French IBAN: positions 4-8 = bank code, 13-24 = account number
bankCode = anIBAN.Middle(4, 5)
accountNumber = anIBAN.Middle(13, 11)
Case "GB"
// British IBAN: positions 4-7 = bank code, 8-21 = account number
bankCode = anIBAN.Middle(4, 4)
accountNumber = anIBAN.Middle(8, 14)
Case Else
// Generic fallback: first 8 chars after check digits as bank code
bankCode = anIBAN.Middle(4, 8)
accountNumber = anIBAN.Middle(12)
End Select
// Query the banks table to retrieve BIC and bank name by bank code (BLZ)
Var db As New Module_WAGDatenbank.WAG3Connection
Try
db.Connect
Var rs As Rowset = db.SelectSQL("SELECT bic, bezeichnung FROM wag5_banken WHERE bankleitzahl = ? LIMIT 1", bankCode.ConvertEncoding(Encodings.ISOLatin1))
If rs Is Nil Or rs.AfterLastRow Then
Return Nil
End If
// Build and return result array: [bankCode, accountNumber, bic, bankName]
Dim result() As String
result.Add(bankCode)
result.Add(accountNumber)
result.Add(rs.Column("bic").StringValue.DefineEncoding(Encodings.ISOLatin1))
result.Add(rs.Column("bezeichnung").StringValue.DefineEncoding(Encodings.ISOLatin1))
rs.Close
Return result
Catch err As DatabaseException
End Try
Return Nil
End Function
Private Function VerifyIBANCountry(iban As String) As Boolean
// Liste der gemäß ISO 3166-1 Alpha-2-Standard anerkannten Ländercodes
Dim paysConnus() As String = Array ("AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", _
"AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", _
"BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", _
"BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", _
"CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", _
"CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", _
"DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", _
"FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", _
"GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", _
"GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", _
"ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", _
"JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", _
"KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", _
"LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", _
"MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", _
"MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", _
"NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", _
"NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", _
"PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", _
"RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", _
"SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", _
"SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", _
"TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", _
"UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", _
"VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW")
// Extrahieren Sie die ersten beiden Buchstaben der IBAN.
Dim countryCode As String = iban.Left(2)
// Prüfen Sie, ob der Ländercode in der Liste der bekannten Länder enthalten ist.'
For Each pays As String In paysConnus
If countryCode = pays Then
Return True
End If
Next
// Wenn der Ländercode nicht in der Liste der bekannten Länder enthalten ist
Return False
End Function
Private Function IsValidIBANLength(anIBAN As String) As Boolean
// Validate IBAN length per country code according to the official IBAN registry.
// Each country defines a fixed total length for its IBANs.
// Returns False if the country is unknown or the length does not match.
Dim countryCode As String = anIBAN.Left(2)
Dim expectedLength As Integer
Select Case countryCode
Case "AD"
expectedLength = 24
Case "AE"
expectedLength = 23
Case "AL"
expectedLength = 28
Case "AT"
expectedLength = 20
Case "AZ"
expectedLength = 28
Case "BA"
expectedLength = 20
Case "BE"
expectedLength = 16
Case "BG"
expectedLength = 22
Case "BH"
expectedLength = 22
Case "BR"
expectedLength = 29
Case "BY"
expectedLength = 28
Case "CH"
expectedLength = 21
Case "CR"
expectedLength = 22
Case "CY"
expectedLength = 28
Case "CZ"
expectedLength = 24
Case "DE"
expectedLength = 22
Case "DJ"
expectedLength = 27
Case "DK"
expectedLength = 18
Case "DO"
expectedLength = 28
Case "EE"
expectedLength = 20
Case "EG"
expectedLength = 29
Case "ES"
expectedLength = 24
Case "FI"
expectedLength = 18
Case "FO"
expectedLength = 18
Case "FR"
expectedLength = 27
Case "GB"
expectedLength = 22
Case "GE"
expectedLength = 22
Case "GI"
expectedLength = 23
Case "GL"
expectedLength = 18
Case "GR"
expectedLength = 27
Case "GT"
expectedLength = 28
Case "HR"
expectedLength = 21
Case "HU"
expectedLength = 28
Case "IE"
expectedLength = 22
Case "IL"
expectedLength = 23
Case "IQ"
expectedLength = 23
Case "IS"
expectedLength = 26
Case "IT"
expectedLength = 27
Case "JO"
expectedLength = 30
Case "KW"
expectedLength = 30
Case "KZ"
expectedLength = 20
Case "LB"
expectedLength = 28
Case "LC"
expectedLength = 32
Case "LI"
expectedLength = 21
Case "LT"
expectedLength = 20
Case "LU"
expectedLength = 20
Case "LV"
expectedLength = 21
Case "LY"
expectedLength = 25
Case "MC"
expectedLength = 27
Case "MD"
expectedLength = 24
Case "ME"
expectedLength = 22
Case "MK"
expectedLength = 19
Case "MR"
expectedLength = 27
Case "MT"
expectedLength = 31
Case "MU"
expectedLength = 30
Case "NI"
expectedLength = 28
Case "NL"
expectedLength = 18
Case "NO"
expectedLength = 15
Case "PK"
expectedLength = 24
Case "PL"
expectedLength = 28
Case "PS"
expectedLength = 29
Case "PT"
expectedLength = 25
Case "QA"
expectedLength = 29
Case "RO"
expectedLength = 24
Case "RS"
expectedLength = 22
Case "RU"
expectedLength = 33
Case "SA"
expectedLength = 24
Case "SC"
expectedLength = 31
Case "SD"
expectedLength = 18
Case "SE"
expectedLength = 24
Case "SI"
expectedLength = 19
Case "SK"
expectedLength = 24
Case "SM"
expectedLength = 27
Case "ST"
expectedLength = 25
Case "SV"
expectedLength = 28
Case "TL"
expectedLength = 23
Case "TN"
expectedLength = 24
Case "TR"
expectedLength = 26
Case "UA"
expectedLength = 29
Case "VA"
expectedLength = 22
Case "VG"
expectedLength = 24
Case "XK"
expectedLength = 20
Case Else
Return False
End Select
Return anIBAN.Length = expectedLength
End Function
I didn’t notice that IBAN had different lengths depending on the country…
I wasn’t aware of that either, until Claude.ai pointed it out to me.
A tip for anyone wanting to set up a suitable MySQL table: Many banks offer a CSV file containing information about banks in their own country.
For Germany, for example, Deutsche Bank offers something like this at Bankleitzahlen | Deutsche Bundesbank.
you also have a lot of them here
Just a short reminder: BIC codes are changing from time to time - in Germany the Deutsche Bundesbank sends out a list of changes every three months…
So if you rely on a correct list you have to update it frequently…
Thanks to everybody, seems as I can get on now!