├── LICENSE ├── README.md ├── countryList.go ├── data └── iban.json ├── iban.go └── iban_test.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Pascal Paulus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iban 2 | GoLang IBAN Validation module 3 | 4 | The separate BBAN ckeck is not yet implemented. 5 | This is needed for the countries where the IBAN ckecksum is a constant. 6 | Currently the validation will work but the constant is not checked and neiter the BBAN. 7 | Concerned countries: 8 | Macedonia, Bosnia and Herzegovina, East Timor, Mauritania, Montenegro, Portugal, Slovenia, Tunisia 9 | 10 | The IBAN may be formated with spaces. Letter cases are ignored. 11 | 12 | Here a small sample to test it. 13 | 14 | 15 | ```go 16 | package main 17 | 18 | import ( 19 | "fmt" 20 | "github.com/go-pascal/iban" 21 | ) 22 | 23 | func main() { 24 | 25 | var OK, well_formated, err = iban.IsCorrectIban("GB82 WEST 1234 5698 7654 32 ", true) // passed: IBAN string , debug true/false 26 | if err != nil { 27 | fmt.Println(err.Error()) 28 | } else { 29 | 30 | if OK { 31 | fmt.Printf("IBAN %s is valid \n\r", well_formated) 32 | } else { 33 | fmt.Println("IBAN is not valid") 34 | } 35 | } 36 | 37 | var ck, err2 = iban.GetIbanChecksum("GB00 WEST 1234 5698 7654 32 ") 38 | if err2 != nil { 39 | fmt.Println(err2.Error()) 40 | } else { 41 | 42 | fmt.Println("IBAN checksum :", ck) 43 | } 44 | } 45 | ``` 46 | 47 | ```go 48 | package main 49 | 50 | import "github.com/RitchieFlick/iban" 51 | import "log" 52 | 53 | func main() { 54 | iban, err := iban.NewIBAN("GB82WEST12345698765432") 55 | if err != nil { 56 | log.Print(err) 57 | } 58 | log.Print(iban.Number) 59 | } 60 | 61 | ``` 62 | -------------------------------------------------------------------------------- /countryList.go: -------------------------------------------------------------------------------- 1 | package iban 2 | 3 | var countryList = map[string]ibanCountry{ 4 | "AD": {country: "Andorra", chars: 24, bbanFormat: "8n,12c", code: "AD", ibanFields: "ADkk bbbb ssss cccc cccc cccc", comment: "b = National bank code s = Branch code c = Account number", standardTreatment: true}, 5 | "AE": {country: "United Arab Emirates", chars: 23, bbanFormat: "3n,16n", code: "AE", ibanFields: "AEkk bbbc cccc cccc cccc ccc", comment: "b = National bank code c = Account number ", standardTreatment: true}, 6 | "AL": {country: "Albania", chars: 28, bbanFormat: "8n, 16c", code: "AL", ibanFields: "ALkk bbbs sssx cccc cccc cccc cccc", comment: "b = National bank code s = Branch code x = National check digit c = Account number", standardTreatment: true}, 7 | "AO": {country: "Angola", chars: 25, bbanFormat: "21n", code: "AO", ibanFields: "AOkk bbbb cccc cccc cccc cccx", comment: "b = Bank code; c = Account number; x = Check digit", standardTreatment: true}, 8 | "AT": {country: "Austria", chars: 20, bbanFormat: "16n", code: "AT", ibanFields: "ATkk bbbb bccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 9 | "AZ": {country: "Azerbaijan", chars: 28, bbanFormat: "4c,20n", code: "AZ", ibanFields: "AZkk bbbb cccc cccc cccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 10 | "BA": {country: "Bosnia and Herzegovina", chars: 20, bbanFormat: "16n", code: "BA", ibanFields: "BAkk bbbs sscc cccc ccxx", comment: "k = IBAN check digits (always 39) b = National bank code s = Branch code c = Account number x = National check digits", standardTreatment: true}, 11 | "BE": {country: "Belgium", chars: 16, bbanFormat: "12n", code: "BE", ibanFields: "BEkk bbbc cccc ccxx", comment: "b = National bank code c = Account number x = National check digits", standardTreatment: true}, 12 | "BF": {country: "Burkina Faso", chars: 28, bbanFormat: "24n", code: "BF", ibanFields: "BFkk bbbb ssss cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 13 | "BG": {country: "Bulgaria", chars: 22, bbanFormat: "4a,6n,8c", code: "BG", ibanFields: "BGkk bbbb ssss ddcc cccc cc", comment: "b = BIC bank code s = Branch (BAE) number d = Account type c = Account number", standardTreatment: true}, 14 | "BH": {country: "Bahrain", chars: 22, bbanFormat: "4a,14c", code: "BH", ibanFields: "BHkk bbbb cccc cccc cccc cc", comment: "b = National bank code c = Account number", standardTreatment: true}, 15 | "BI": {country: "Burundi", chars: 16, bbanFormat: "12n", code: "BI", ibanFields: "BIkk bbbb cccc cccc", comment: "b = Bank code; c = Account number", standardTreatment: true}, 16 | "BJ": {country: "Benin", chars: 28, bbanFormat: "24n", code: "BJ", ibanFields: "BJkk bbbb ssss cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 17 | "BL": {country: "Saint Barthélemy", chars: 27, bbanFormat: "10n,11c,2n", code: "BL", ibanFields: "BLkk bbbb bsss sscc cccc cccc cxx", comment: "b = Bank code; s = Branch code; c = Account number; x = National check digits", standardTreatment: true}, 18 | "BR": {country: "Brazil", chars: 29, bbanFormat: "23n, 1a, 1c", code: "BR", ibanFields: "BRkk bbbb bbbb ssss sccc cccc ccct n", comment: "k = IBAN check digits (Calculated by MOD 97-10) b = National bank code s = Branch code c = Account Number t = Account type (Cheque account, Savings account etc.) n = Owner account number (1, 2 etc.)[31]", standardTreatment: true}, 19 | "BY": {country: "Belarus", chars: 28, bbanFormat: "4c,20n", code: "BY", ibanFields: "BYkk bbbb cccc cccc cccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 20 | "CF": {country: "Central African Republic", chars: 27, bbanFormat: "23n", code: "CF", ibanFields: "CFkk bbbb ssss cccc cccc cccc ccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 21 | "CG": {country: "Congo", chars: 27, bbanFormat: "23n", code: "CG", ibanFields: "CGkk bbbb ssss cccc cccc cccc ccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 22 | "CH": {country: "Switzerland", chars: 21, bbanFormat: "5n,12c", code: "CH", ibanFields: "CHkk bbbb bccc cccc cccc c", comment: "b = National bank code c = Account number", standardTreatment: true}, 23 | "CI": {country: "Ivory Coast", chars: 28, bbanFormat: "24n", code: "CI", ibanFields: "CIkk bbbb ssss cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 24 | "CM": {country: "Cameroon", chars: 27, bbanFormat: "23n", code: "CM", ibanFields: "CMkk bbbb ssss cccc cccc cccc ccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 25 | "CR": {country: "Costa Rica", chars: 22, bbanFormat: "17n", code: "CR", ibanFields: "CRkk bbbc cccc cccc cccc c", comment: "b = bank code c = Account number", standardTreatment: false}, 26 | "CV": {country: "Cape Verde", chars: 25, bbanFormat: "21n", code: "CV", ibanFields: "CVkk bbbb ssss cccc cccc cccx", comment: "b = Bank code; s = Branch code; c = Account number; x = Check digit", standardTreatment: true}, 27 | "CY": {country: "Cyprus", chars: 28, bbanFormat: "8n,16c", code: "CY", ibanFields: "CYkk bbbs ssss cccc cccc cccc cccc", comment: "b = National bank code s = Branch code c = Account number", standardTreatment: true}, 28 | "CZ": {country: "Czech Republic", chars: 24, bbanFormat: "20n", code: "CZ", ibanFields: "CZkk bbbb ssss sscc cccc cccc", comment: "b = National bank code s = Account number prefix c = Account number", standardTreatment: true}, 29 | "DE": {country: "Germany", chars: 22, bbanFormat: "18n", code: "DE", ibanFields: "DEkk bbbb bbbb cccc cccc cc", comment: "b = Bank and branch identifier (de:Bankleitzahl or BLZ) c = Account number", standardTreatment: true}, 30 | "DJ": {country: "Djibouti", chars: 27, bbanFormat: "23n", code: "DJ", ibanFields: "DJkk bbbb ssss cccc cccc cccc ccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 31 | "DK": {country: "Denmark", chars: 18, bbanFormat: "14n", code: "DK", ibanFields: "DKkk bbbb cccc cccc cc", comment: "b = National bank code c = Account number", standardTreatment: true}, 32 | "DO": {country: "Dominican Republic", chars: 28, bbanFormat: "4a,20n", code: "DO", ibanFields: "DOkk bbbb cccc cccc cccc cccc cccc", comment: "b = Bank identifier c = Account number", standardTreatment: true}, 33 | "DZ": {country: "Algeria", chars: 26, bbanFormat: "20n", code: "DZ", ibanFields: "DZkk bbbb ssss cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 34 | "EE": {country: "Estonia", chars: 20, bbanFormat: "16n", code: "EE", ibanFields: "EEkk bbss cccc cccc cccx", comment: "b = National bank code s = Branch code c = Account number x = National check digit", standardTreatment: true}, 35 | "EG": {country: "Egypt", chars: 29, bbanFormat: "25n", code: "EG", ibanFields: "EGkk bbbb ssss cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 36 | "ES": {country: "Spain", chars: 24, bbanFormat: "20n", code: "ES", ibanFields: "ESkk bbbb gggg xxcc cccc cccc", comment: "b = National bank code g = Branch code x = Check digits c = Account number", standardTreatment: true}, 37 | "FI": {country: "Finland", chars: 18, bbanFormat: "14n", code: "FI", ibanFields: "FIkk bbbb bbcc cccc cx", comment: "b = Bank and branch code c = Account number x = National check digit", standardTreatment: true}, 38 | "FO": {country: "Faroe Islands", chars: 18, bbanFormat: "14n", code: "FO", ibanFields: "FOkk bbbb cccc cccc cx", comment: "b = National bank code c = Account number x = National check digit", standardTreatment: true}, 39 | "FR": {country: "France", chars: 27, bbanFormat: "10n,11c,2n", code: "FR", ibanFields: "FRkk bbbb bggg ggcc cccc cccc cxx", comment: "b = National bank code g = Branch code (fr:code guichet) c = Account number x = National check digits (fr:clé RIB)", standardTreatment: true}, 40 | "GA": {country: "Gabon", chars: 27, bbanFormat: "23n", code: "GA", ibanFields: "GAkk bbbb ssss cccc cccc cccc ccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 41 | "GB": {country: "United Kingdom", chars: 22, bbanFormat: "4a,14n", code: "GB", ibanFields: "GBkk bbbb ssss sscc cccc cc", comment: "b = BIC bank code s = Bank and branch code (sort code) c = Account number", standardTreatment: true}, 42 | "GE": {country: "Georgia", chars: 22, bbanFormat: "2c,16n", code: "GE", ibanFields: "GEkk bbcc cccc cccc cccc cc", comment: "b = National bank code c = Account number", standardTreatment: true}, 43 | "GG": {country: "Guernsey", chars: 22, bbanFormat: "4a,14n", code: "GG", ibanFields: "GGkk bbbb ssss sscc cccc cc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 44 | "GI": {country: "Gibraltar", chars: 23, bbanFormat: "4a,15c", code: "GI", ibanFields: "GIkk bbbb cccc cccc cccc ccc", comment: "b = BIC bank code c = Account number", standardTreatment: true}, 45 | "GL": {country: "Greenland", chars: 18, bbanFormat: "14n", code: "GL", ibanFields: "GLkk bbbb cccc cccc cc", comment: "b = National bank code c = Account number", standardTreatment: true}, 46 | "GQ": {country: "Equatorial Guinea", chars: 27, bbanFormat: "23n", code: "GQ", ibanFields: "GQkk bbbb ssss cccc cccc cccc ccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 47 | "GR": {country: "Greece", chars: 27, bbanFormat: "7n,16c", code: "GR", ibanFields: "GRkk bbbs sssc cccc cccc cccc ccc", comment: "b = National bank code s = Branch code c = Account number", standardTreatment: true}, 48 | "GT": {country: "Guatemala", chars: 28, bbanFormat: "4c,20c", code: "GT", ibanFields: "GTkk bbbb mmtt cccc cccc cccc cccc", comment: "b = National bank code c = Account number m = Currency t = Account type ", standardTreatment: true}, 49 | "GW": {country: "Guinea Bissau", chars: 25, bbanFormat: "21n", code: "GW", ibanFields: "GWkk bbbb ssss cccc cccc cccx", comment: "b = Bank code; s = Branch code; c = Account number; x = Check digit", standardTreatment: true}, 50 | "HN": {country: "Honduras", chars: 28, bbanFormat: "24n", code: "HN", ibanFields: "HNkk pppp cccc cccc cccc cccc cccc", comment: "p = Bank identifier code; c = Account number", standardTreatment: true}, 51 | "HR": {country: "Croatia", chars: 21, bbanFormat: "17n", code: "HR", ibanFields: "HRkk bbbb bbbc cccc cccc c", comment: "b = Bank code c = Account number", standardTreatment: true}, 52 | "HU": {country: "Hungary", chars: 28, bbanFormat: "24n", code: "HU", ibanFields: "HUkk bbbs sssk cccc cccc cccc cccx", comment: "b = National bank code s = Branch code c = Account number x = National check digit", standardTreatment: true}, 53 | "IE": {country: "Ireland", chars: 22, bbanFormat: "4c,14n", code: "IE", ibanFields: "IEkk aaaa bbbb bbcc cccc cc", comment: "a = BIC bank code b = Bank/branch code (sort code) c = Account number", standardTreatment: true}, 54 | "IK": {country: "Israel", chars: 23, bbanFormat: "19n", code: "IK", ibanFields: "ILkk bbbn nncc cccc cccc ccc", comment: "b = National bank code n = Branch number c = Account number 13 digits (padded with zeros)", standardTreatment: true}, 55 | "IL": {country: "Israel", chars: 23, bbanFormat: "4c,15n", code: "IL", ibanFields: "ILkk bbbb cccc cccc cccc ccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 56 | "IM": {country: "Isle of Man", chars: 22, bbanFormat: "4a,14n", code: "IM", ibanFields: "IMkk bbbb ssss sscc cccc cc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 57 | "IQ": {country: "Iraq", chars: 23, bbanFormat: "4c,15n", code: "IQ", ibanFields: "IQkk bbbb cccc cccc cccc ccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 58 | "IR": {country: "Iran", chars: 26, bbanFormat: "22n", code: "IR", ibanFields: "IRkk pppp cccc cccc cccc cccc cc", comment: "p = Bank code; c = Account number", standardTreatment: true}, 59 | "IS": {country: "Iceland", chars: 26, bbanFormat: "22n", code: "IS", ibanFields: "ISkk bbbb sscc cccc iiii iiii ii", comment: "b = National bank code s = Branch code c = Account number i = holder's kennitala (national identification number).", standardTreatment: true}, 60 | "IT": {country: "Italy", chars: 27, bbanFormat: "1a,10n,12c", code: "IT", ibanFields: "ITkk xaaa aabb bbbc cccc cccc ccc", comment: "x = Check char (CIN) a = National bank code (it:Associazione bancaria italiana or Codice ABI ) b = Branch code (it:Coordinate bancarie or CAB – Codice d'Avviamento Bancario) c = Account number", standardTreatment: true}, 61 | "JE": {country: "Jersey", chars: 22, bbanFormat: "4a,14n", code: "JE", ibanFields: "JEkk bbbb ssss sscc cccc cc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 62 | "JO": {country: "Jordan", chars: 30, bbanFormat: "4a, 22n", code: "JO", ibanFields: "JOkk bbbb nnnn cccc cccc cccc cccc cc", comment: "b = National bank code n = Branch code c = Account number ", standardTreatment: true}, 63 | "KM": {country: "Comoros", chars: 27, bbanFormat: "23n", code: "KM", ibanFields: "KMkk bbbb ssss cccc cccc cccc ccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 64 | "KW": {country: "Kuwait", chars: 30, bbanFormat: "4a, 22c", code: "KW", ibanFields: "KWkk bbbb cccc cccc cccc cccc cccc cc", comment: "b = National bank code c = Account number.", standardTreatment: true}, 65 | "KZ": {country: "Kazakhstan", chars: 20, bbanFormat: "3n,13c", code: "KZ", ibanFields: "KZkk bbbc cccc cccc cccc", comment: "b = National bank code c = Account number ", standardTreatment: true}, 66 | "LB": {country: "Lebanon", chars: 28, bbanFormat: "4n,20c", code: "LB", ibanFields: "LBkk bbbb cccc cccc cccc cccc cccc", comment: "b = Bank code; c = Account number", standardTreatment: true}, 67 | "LC": {country: "Saint Lucia", chars: 32, bbanFormat: "4c,24n", code: "LC", ibanFields: "LCkk bbbb cccc cccc cccc ccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 68 | "LI": {country: "Liechtenstein", chars: 21, bbanFormat: "5n,12c", code: "LI", ibanFields: "LIkk bbbb bccc cccc cccc c", comment: "b = National bank code c = Account number", standardTreatment: true}, 69 | "LT": {country: "Lithuania", chars: 20, bbanFormat: "16n", code: "LT", ibanFields: "LTkk bbbb bccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 70 | "LU": {country: "Luxembourg", chars: 20, bbanFormat: "3n,13c", code: "LU", ibanFields: "LUkk bbbc cccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 71 | "LV": {country: "Latvia", chars: 21, bbanFormat: "4a,13c", code: "LV", ibanFields: "LVkk bbbb cccc cccc cccc c", comment: "b = BIC Bank code c = Account number", standardTreatment: true}, 72 | "MA": {country: "Morocco", chars: 28, bbanFormat: "24n", code: "MA", ibanFields: "MAkk bbbb ssss cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 73 | "MC": {country: "Monaco", chars: 27, bbanFormat: "10n,11c,2n", code: "MC", ibanFields: "MCkk bbbb bsss sscc cccc cccc cxx", comment: "b = National bank code s = Branch code (fr:code guichet) c = Account number x = National check digits (fr:clé RIB). ", standardTreatment: true}, 74 | "MD": {country: "Moldova", chars: 24, bbanFormat: "2c,18c", code: "MD", ibanFields: "MDkk bbcc cccc cccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 75 | "ME": {country: "Montenegro", chars: 22, bbanFormat: "18n", code: "ME", ibanFields: "MEkk bbbc cccc cccc cccc xx", comment: "k = IBAN check digits (always = '25') b = Bank code c = Account number x = National check digits", standardTreatment: true}, 76 | "MF": {country: "Saint Martin", chars: 27, bbanFormat: "10n,11c,2n", code: "MF", ibanFields: "MFkk bbbb bsss sscc cccc cccc cxx", comment: "b = Bank code; s = Branch code; c = Account number; x = National check digits", standardTreatment: true}, 77 | "MG": {country: "Madagascar", chars: 27, bbanFormat: "23n", code: "MG", ibanFields: "MGkk bbbb ssss cccc cccc cccc ccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 78 | "MK": {country: "Macedonia", chars: 19, bbanFormat: "3n,10c,2n", code: "MK", ibanFields: "MKkk bbbc cccc cccc cxx", comment: "k = IBAN check digits (always = '07') b = National bank code c = Account number x = National check digits", standardTreatment: true}, 79 | "ML": {country: "Mali", chars: 28, bbanFormat: "24n", code: "ML", ibanFields: "MLkk bbbb ssss cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 80 | "MR": {country: "Mauritania", chars: 27, bbanFormat: "23n", code: "MR", ibanFields: "MRkk bbbb bsss sscc cccc cccc cxx", comment: "k = IBAN check digits (always 13) b = National bank code s = Branch code (fr:code guichet) c = Account number x = National check digits (fr:clé RIB)", standardTreatment: true}, 81 | "MT": {country: "Malta", chars: 31, bbanFormat: "4a,5n,18c", code: "MT", ibanFields: "MTkk bbbb ssss sccc cccc cccc cccc ccc", comment: "b = BIC bank code s = Branch code c = Account number", standardTreatment: true}, 82 | "MU": {country: "Mauritius", chars: 30, bbanFormat: "4a,19n,3a", code: "MU", ibanFields: "MUkk bbbb bbss cccc cccc cccc 000d dd", comment: "b = National bank code s = Branch identifier c = Account number 0 = Zeroes d = Currency Symbol ", standardTreatment: true}, 83 | "MZ": {country: "Mozambique", chars: 25, bbanFormat: "21n", code: "MZ", ibanFields: "MZkk bbbb ssss cccc cccc cccx x", comment: "b = Bank code; s = Branch code; c = Account number; x = Check digit", standardTreatment: true}, 84 | "NE": {country: "Niger", chars: 28, bbanFormat: "24n", code: "NE", ibanFields: "NEkk bbbb ssss cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 85 | "NI": {country: "Nicaragua", chars: 32, bbanFormat: "28n", code: "NI", ibanFields: "NIkk bbbb ssss cccc cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 86 | "NL": {country: "Netherlands", chars: 18, bbanFormat: "4a,10n", code: "NL", ibanFields: "NLkk bbbb cccc cccc cc", comment: "b = BIC Bank code c = Account number", standardTreatment: true}, 87 | "NO": {country: "Norway", chars: 15, bbanFormat: "11n", code: "NO", ibanFields: "NOkk bbbb cccc ccx", comment: "b = National bank code c = Account number x = Modulo-11 national check digit", standardTreatment: true}, 88 | "PK": {country: "Pakistan", chars: 24, bbanFormat: "4c,16n", code: "PK", ibanFields: "PKkk bbbb cccc cccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 89 | "PL": {country: "Poland", chars: 28, bbanFormat: "24n", code: "PL", ibanFields: "PLkk bbbs sssx cccc cccc cccc cccc", comment: "b = National bank code s = Branch code x = National check digit c = Account number, ", standardTreatment: true}, 90 | "PS": {country: "Palestinian territories", chars: 29, bbanFormat: "4c,21n", code: "PS", ibanFields: "PSkk bbbb xxxx xxxx xccc cccc cccc c", comment: "b = National bank code c = Account number x = Not specified", standardTreatment: true}, 91 | "PT": {country: "Portugal", chars: 25, bbanFormat: "21n", code: "PT", ibanFields: "PTkk bbbb ssss cccc cccc cccx x", comment: "k = IBAN check digits (always = '50') b = National bank code s = Branch code C = Account number x = National check digit", standardTreatment: true}, 92 | "QA": {country: "Qatar", chars: 29, bbanFormat: "4a, 21c", code: "QA", ibanFields: "QAkk bbbb cccc cccc cccc cccc cccc c", comment: "b = National bank code c = Account number[34]", standardTreatment: true}, 93 | "RE": {country: "Réunion", chars: 27, bbanFormat: "10n,11c,2n", code: "RE", ibanFields: "REkk bbbb bsss sscc cccc cccc cxx", comment: "b = Bank code; s = Branch code; c = Account number; x = National check digits", standardTreatment: true}, 94 | "RO": {country: "Romania", chars: 24, bbanFormat: "4a,16c", code: "RO", ibanFields: "ROkk bbbb cccc cccc cccc cccc", comment: "b = BIC Bank code c = Branch code and account number (bank-specific format) ", standardTreatment: true}, 95 | "RS": {country: "Serbia", chars: 22, bbanFormat: "18n", code: "RS", ibanFields: "RSkk bbbc cccc cccc cccc xx", comment: "b = National bank code c = Account number x = Account check digits", standardTreatment: true}, 96 | "SA": {country: "Saudi Arabia", chars: 24, bbanFormat: "2n,18c", code: "SA", ibanFields: "SAkk bbcc cccc cccc cccc cccc", comment: "b = National bank code c = Account number preceded by zeros, if required", standardTreatment: true}, 97 | "SC": {country: "Seychelles", chars: 31, bbanFormat: "4c,23n", code: "SC", ibanFields: "SCkk bbbb cccc cccc cccc cccc cccc mmm", comment: "b = National bank code c = Account number m = Currency", standardTreatment: true}, 98 | "SE": {country: "Sweden", chars: 24, bbanFormat: "20n", code: "SE", ibanFields: "SEkk bbbc cccc cccc cccc cccc", comment: "b = National bank code c = Account number ", standardTreatment: true}, 99 | "SI": {country: "Slovenia", chars: 19, bbanFormat: "15n", code: "SI", ibanFields: "SIkk bbss sccc cccc cxx", comment: "k = IBAN check digits (always = '56') b = National bank code s = Branch code c = Account number x = National check digits", standardTreatment: true}, 100 | "SK": {country: "Slovakia", chars: 24, bbanFormat: "20n", code: "SK", ibanFields: "SKkk bbbb ssss sscc cccc cccc", comment: "b = National bank code s = Account number prefix c = Account number", standardTreatment: true}, 101 | "SM": {country: "San Marino", chars: 27, bbanFormat: "1a,10n,12c", code: "SM", ibanFields: "SMkk xaaa aabb bbbc cccc cccc ccc", comment: "x = Check char (it:CIN) a = National bank code (it:Associazione bancaria italiana or Codice ABI) b = Branch code (it:Coordinate bancarie or CAB – Codice d'Avviamento Bancario) c = Account number", standardTreatment: true}, 102 | "SN": {country: "Senegal", chars: 28, bbanFormat: "24n", code: "SN", ibanFields: "SNkk bbbb ssss cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 103 | "ST": {country: "Sao Tome and Principe", chars: 25, bbanFormat: "4c,17n", code: "ST", ibanFields: "STkk bbbb cccc cccc cccc cccc c", comment: "b = National bank code c = Account number", standardTreatment: true}, 104 | "SV": {country: "El Salvador", chars: 28, bbanFormat: "4c,20n", code: "SV", ibanFields: "SVkk bbbb cccc cccc cccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 105 | "TD": {country: "Chad", chars: 27, bbanFormat: "23n", code: "TD", ibanFields: "TDkk bbbb ssss cccc cccc cccc ccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 106 | "TG": {country: "Togo", chars: 28, bbanFormat: "24n", code: "TG", ibanFields: "TGkk bbbb ssss cccc cccc cccc cccc", comment: "b = Bank code; s = Branch code; c = Account number", standardTreatment: true}, 107 | "TL": {country: "East Timor", chars: 23, bbanFormat: "19n", code: "TL", ibanFields: "TLkk bbbc cccc cccc cccc cxx", comment: "k = IBAN check digits (always = '38') b = Bank identifier c = Account number x = National check digit", standardTreatment: true}, 108 | "TN": {country: "Tunisia", chars: 24, bbanFormat: "20n", code: "TN", ibanFields: "TNkk bbss sccc cccc cccc cccc", comment: "k = IBAN check digits (always 59) b = National bank code s = Branch code c = Account number", standardTreatment: true}, 109 | "TR": {country: "Turkey", chars: 26, bbanFormat: "5n,17c", code: "TR", ibanFields: "TRkk bbbb bxcc cccc cccc cccc cc", comment: "b = National bank code x = Reserved for future use (currently '0') c = Account number", standardTreatment: true}, 110 | "UA": {country: "Ukraine", chars: 29, bbanFormat: "4c,21n", code: "UA", ibanFields: "UAkk bbbb cccc cccc cccc cccc cccc c", comment: "b = National bank code c = Account number", standardTreatment: true}, 111 | "VA": {country: "Vatican", chars: 22, bbanFormat: "3n,15n", code: "VA", ibanFields: "VAkk bbb cccc cccc cccc ccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 112 | "VG": {country: "Virgin Islands, British", chars: 24, bbanFormat: "4c,16n", code: "VG", ibanFields: "VGkk bbbb cccc cccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 113 | "XK": {country: "Kosovo", chars: 20, bbanFormat: "4n,10n,2n", code: "XK", ibanFields: "XKkk bbbb cccc cccc cccc", comment: "b = National bank code c = Account number", standardTreatment: true}, 114 | "YT": {country: "Mayotte", chars: 27, bbanFormat: "10n,11c,2n", code: "YT", ibanFields: "YTkk bbbb bsss sscc cccc cccc cxx", comment: "b = Bank code; s = Branch code; c = Account number; x = National check digits", standardTreatment: true}, 115 | } 116 | -------------------------------------------------------------------------------- /data/iban.json: -------------------------------------------------------------------------------- 1 | { 2 | "ibans": [ 3 | { 4 | "country": "Andorra", 5 | "code": "AD", 6 | "iban": "AD1400080001001234567890" 7 | }, 8 | { 9 | "country": "Austria", 10 | "code": "AT", 11 | "iban": "AT483200000012345864" 12 | }, 13 | { 14 | "country": "Azerbaijan", 15 | "code": "AZ", 16 | "iban": "AZ96AZEJ00000000001234567890" 17 | }, 18 | { 19 | "country": "Bahrain", 20 | "code": "BH", 21 | "iban": "BH02CITI00001077181611" 22 | }, 23 | { 24 | "country": "Belarus", 25 | "code": "BY", 26 | "iban": "BY86AKBB10100000002966000000" 27 | }, 28 | { 29 | "country": "Belgium", 30 | "code": "BE", 31 | "iban": "BE71096123456769" 32 | }, 33 | { 34 | "country": "Bosnia and Herzegovina", 35 | "code": "BA", 36 | "iban": "BA275680000123456789" 37 | }, 38 | { 39 | "country": "Brazil", 40 | "code": "BR", 41 | "iban": "BR1500000000000010932840814P2" 42 | }, 43 | { 44 | "country": "Bulgaria", 45 | "code": "BG", 46 | "iban": "BG18RZBB91550123456789" 47 | }, 48 | { 49 | "country": "Costa Rica", 50 | "code": "CR", 51 | "iban": "CR37012600000123456789" 52 | }, 53 | { 54 | "country": "Croatia", 55 | "code": "HR", 56 | "iban": "HR1723600001101234565" 57 | }, 58 | { 59 | "country": "Cyprus", 60 | "code": "CY", 61 | "iban": "CY21002001950000357001234567" 62 | }, 63 | { 64 | "country": "Czech Republic", 65 | "code": "CZ", 66 | "iban": "CZ5508000000001234567899" 67 | }, 68 | { 69 | "country": "Denmark", 70 | "code": "DK", 71 | "iban": "DK9520000123456789" 72 | }, 73 | { 74 | "country": "Dominican Republic", 75 | "code": "DO", 76 | "iban": "DO22ACAU00000000000123456789" 77 | }, 78 | { 79 | "country": "El Salvador", 80 | "code": "SV", 81 | "iban": "SV43ACAT00000000000000123123" 82 | }, 83 | { 84 | "country": "Estonia", 85 | "code": "EE", 86 | "iban": "EE471000001020145685" 87 | }, 88 | { 89 | "country": "Faroe Islands", 90 | "code": "FO", 91 | "iban": "FO9264600123456789" 92 | }, 93 | { 94 | "country": "Finland", 95 | "code": "FI", 96 | "iban": "FI1410093000123458" 97 | }, 98 | { 99 | "country": "France", 100 | "code": "FR", 101 | "iban": "FR7630006000011234567890189" 102 | }, 103 | { 104 | "country": "Georgia", 105 | "code": "GE", 106 | "iban": "GE60NB0000000123456789" 107 | }, 108 | { 109 | "country": "Germany", 110 | "code": "DE", 111 | "iban": "DE91100000000123456789" 112 | }, 113 | { 114 | "country": "Gibraltar", 115 | "code": "GI", 116 | "iban": "GI04BARC000001234567890" 117 | }, 118 | { 119 | "country": "Greece", 120 | "code": "GR", 121 | "iban": "GR9608100010000001234567890" 122 | }, 123 | { 124 | "country": "Greenland", 125 | "code": "GL", 126 | "iban": "GL8964710123456789" 127 | }, 128 | { 129 | "country": "Guatemala", 130 | "code": "GT", 131 | "iban": "GT20AGRO00000000001234567890" 132 | }, 133 | { 134 | "country": "Hungary", 135 | "code": "HU", 136 | "iban": "HU93116000060000000012345676" 137 | }, 138 | { 139 | "country": "Iceland", 140 | "code": "IS", 141 | "iban": "IS030001121234561234567890" 142 | }, 143 | { 144 | "country": "Iraq", 145 | "code": "IQ", 146 | "iban": "IQ20CBIQ861800101010500" 147 | }, 148 | { 149 | "country": "Ireland", 150 | "code": "IE", 151 | "iban": "IE64IRCE92050112345678" 152 | }, 153 | { 154 | "country": "Israel", 155 | "code": "IL", 156 | "iban": "IL170108000000012612345" 157 | }, 158 | { 159 | "country": "Italy", 160 | "code": "IT", 161 | "iban": "IT60X0542811101000000123456" 162 | }, 163 | { 164 | "country": "Jordan", 165 | "code": "JO", 166 | "iban": "JO71CBJO0000000000001234567890" 167 | }, 168 | { 169 | "country": "Kazakhstan", 170 | "code": "KZ", 171 | "iban": "KZ563190000012344567" 172 | }, 173 | { 174 | "country": "Kosovo", 175 | "code": "XK", 176 | "iban": "XK051212012345678906" 177 | }, 178 | { 179 | "country": "Kuwait", 180 | "code": "KW", 181 | "iban": "KW81CBKU0000000000001234560101" 182 | }, 183 | { 184 | "country": "Latvia", 185 | "code": "LV", 186 | "iban": "LV97HABA0012345678910" 187 | }, 188 | { 189 | "country": "Lebanon", 190 | "code": "LB", 191 | "iban": "LB92000700000000123123456123" 192 | }, 193 | { 194 | "country": "Liechtenstein", 195 | "code": "LI", 196 | "iban": "LI7408806123456789012" 197 | }, 198 | { 199 | "country": "Lithuania", 200 | "code": "LT", 201 | "iban": "LT601010012345678901" 202 | }, 203 | { 204 | "country": "Luxembourg", 205 | "code": "LU", 206 | "iban": "LU120010001234567891" 207 | }, 208 | { 209 | "country": "Macedonia", 210 | "code": "MK", 211 | "iban": "MK07200002785123453" 212 | }, 213 | { 214 | "country": "Malta", 215 | "code": "MT", 216 | "iban": "MT31MALT01100000000000000000123" 217 | }, 218 | { 219 | "country": "Mauritania", 220 | "code": "MR", 221 | "iban": "MR1300020001010000123456753" 222 | }, 223 | { 224 | "country": "Mauritius", 225 | "code": "MU", 226 | "iban": "MU43BOMM0101123456789101000MUR" 227 | }, 228 | { 229 | "country": "Moldova", 230 | "code": "MD", 231 | "iban": "MD21EX000000000001234567" 232 | }, 233 | { 234 | "country": "Monaco", 235 | "code": "MC", 236 | "iban": "MC5810096180790123456789085" 237 | }, 238 | { 239 | "country": "Montenegro", 240 | "code": "ME", 241 | "iban": "ME25505000012345678951" 242 | }, 243 | { 244 | "country": "Netherlands", 245 | "code": "NL", 246 | "iban": "NL02ABNA0123456789" 247 | }, 248 | { 249 | "country": "Norway", 250 | "code": "NO", 251 | "iban": "NO8330001234567" 252 | }, 253 | { 254 | "country": "Pakistan", 255 | "code": "PK", 256 | "iban": "PK36SCBL0000001123456702" 257 | }, 258 | { 259 | "country": "Palestine", 260 | "code": "PS", 261 | "iban": "PS92PALS000000000400123456702" 262 | }, 263 | { 264 | "country": "Poland", 265 | "code": "PL", 266 | "iban": "PL10105000997603123456789123" 267 | }, 268 | { 269 | "country": "Portugal", 270 | "code": "PT", 271 | "iban": "PT50002700000001234567833" 272 | }, 273 | { 274 | "country": "Qatar", 275 | "code": "QA", 276 | "iban": "QA54QNBA000000000000693123456" 277 | }, 278 | { 279 | "country": "Romania", 280 | "code": "RO", 281 | "iban": "RO09BCYP0000001234567890" 282 | }, 283 | { 284 | "country": "Saint Lucia", 285 | "code": "LC", 286 | "iban": "LC14BOSL123456789012345678901234" 287 | }, 288 | { 289 | "country": "San Marino", 290 | "code": "SM", 291 | "iban": "SM76P0854009812123456789123" 292 | }, 293 | { 294 | "country": "Sao Tome and Principe", 295 | "code": "ST", 296 | "iban": "ST23000200000289355710148" 297 | }, 298 | { 299 | "country": "Saudi", 300 | "code": "Arabia", 301 | "iban": "SA4420000001234567891234" 302 | }, 303 | { 304 | "country": "Serbia", 305 | "code": "RS", 306 | "iban": "RS35105008123123123173" 307 | }, 308 | { 309 | "country": "Seychelles", 310 | "code": "SC", 311 | "iban": "SC52BAHL01031234567890123456USD" 312 | }, 313 | { 314 | "country": "Slovak Republic", 315 | "code": "SK", 316 | "iban": "SK8975000000000012345671" 317 | }, 318 | { 319 | "country": "Slovenia", 320 | "code": "SI", 321 | "iban": "SI56192001234567892" 322 | }, 323 | { 324 | "country": "Spain", 325 | "code": "ES", 326 | "iban": "ES7921000813610123456789" 327 | }, 328 | { 329 | "country": "Sweden", 330 | "code": "SE", 331 | "iban": "SE1412345678901234567890" 332 | }, 333 | { 334 | "country": "Switzerland", 335 | "code": "CH", 336 | "iban": "CH5604835012345678009" 337 | }, 338 | { 339 | "country": "Timor Leste", 340 | "code": "TL", 341 | "iban": "TL380080012345678910157" 342 | }, 343 | { 344 | "country": "Tunisia", 345 | "code": "TN", 346 | "iban": "TN4401000067123456789123" 347 | }, 348 | { 349 | "country": "Turkey", 350 | "code": "TR", 351 | "iban": "TR320010009999901234567890" 352 | }, 353 | { 354 | "country": "Ukraine", 355 | "code": "UA", 356 | "iban": "UA903052992990004149123456789" 357 | }, 358 | { 359 | "country": "United Arab Emirates", 360 | "code": "AE", 361 | "iban": "AE460090000000123456789" 362 | }, 363 | { 364 | "country": "United Kingdom", 365 | "code": "GB", 366 | "iban": "GB98MIDL07009312345678" 367 | }, 368 | { 369 | "country": "Vatican", 370 | "code": "VA", 371 | "iban": "VA54001000000017267005" 372 | }, 373 | { 374 | "country": "Virgin Islands British", 375 | "code": "VG", 376 | "iban": "VG21PACG0000000123456789" 377 | }, 378 | { 379 | "country": "Algeria", 380 | "code": "DZ", 381 | "iban": "DZ580002100007113001511433" 382 | }, 383 | { 384 | "country": "Angola", 385 | "code": "AO", 386 | "iban": "AO06004400006729503010102" 387 | }, 388 | { 389 | "country": "Benin", 390 | "code": "BJ", 391 | "iban": "BJ66BJ0610100100144390000769" 392 | }, 393 | { 394 | "country": "Burkina Faso", 395 | "code": "BF", 396 | "iban": "BF42BF0840101300463574000390" 397 | }, 398 | { 399 | "country": "Burundi", 400 | "code": "BI", 401 | "iban": "BI43201011067444" 402 | }, 403 | { 404 | "country": "Cameroon", 405 | "code": "CM", 406 | "iban": "CM2110002000300277976315008" 407 | }, 408 | { 409 | "country": "Cape Verde", 410 | "code": "CV", 411 | "iban": "CV64000500000020108215144" 412 | }, 413 | { 414 | "country": "Central African Republic", 415 | "code": "CF", 416 | "iban": "CF4220001000010120069700160" 417 | }, 418 | { 419 | "country": "Chad", 420 | "code": "TD", 421 | "iban": "TD8960002000010271091600153" 422 | }, 423 | { 424 | "country": "Comoros", 425 | "code": "KM", 426 | "iban": "KM4600005000010010904400137" 427 | }, 428 | { 429 | "country": "Congo", 430 | "code": "CG", 431 | "iban": "CG3930011000101013451300019" 432 | }, 433 | { 434 | "country": "Djibouti", 435 | "code": "DJ", 436 | "iban": "DJ2110002010010409943020008" 437 | }, 438 | { 439 | "country": "Egypt", 440 | "code": "EG", 441 | "iban": "EG210003700067100239218937900" 442 | }, 443 | { 444 | "country": "Equatorial", 445 | "code": "Guinea", 446 | "iban": "GQ7050002001003715228190196" 447 | }, 448 | { 449 | "country": "Gabon", 450 | "code": "GA", 451 | "iban": "GA2140021010032001890020126" 452 | }, 453 | { 454 | "country": "Guinea Bissau", 455 | "code": "GB", 456 | "iban": "GW04GW1430010181800637601" 457 | }, 458 | { 459 | "country": "Honduras", 460 | "code": "HN", 461 | "iban": "HN54PISA00000000000000123124" 462 | }, 463 | { 464 | "country": "Iran", 465 | "code": "IR", 466 | "iban": "IR710570029971601460641001" 467 | }, 468 | { 469 | "country": "Ivory", 470 | "code": "Coast", 471 | "iban": "CI93CI0080111301134291200589" 472 | }, 473 | { 474 | "country": "Madagascar", 475 | "code": "MG", 476 | "iban": "MG4600005030071289421016045" 477 | }, 478 | { 479 | "country": "Mali", 480 | "code": "ML", 481 | "iban": "ML13ML0160120102600100668497" 482 | }, 483 | { 484 | "country": "Morocco", 485 | "code": "MA", 486 | "iban": "MA64011519000001205000534921" 487 | }, 488 | { 489 | "country": "Mozambique", 490 | "code": "MZ", 491 | "iban": "MZ59000301080016367102371" 492 | }, 493 | { 494 | "country": "Nicaragua", 495 | "code": "NI", 496 | "iban": "NI92BAMC000000000000000003123123" 497 | }, 498 | { 499 | "country": "Niger", 500 | "code": "NE", 501 | "iban": "NE58NE0380100100130305000268" 502 | }, 503 | { 504 | "country": "Senegal", 505 | "code": "SN", 506 | "iban": "SN08SN0100152000048500003035" 507 | }, 508 | { 509 | "country": "Togo", 510 | "code": "TG", 511 | "iban": "TG53TG0090604310346500400070" 512 | } 513 | ] 514 | } -------------------------------------------------------------------------------- /iban.go: -------------------------------------------------------------------------------- 1 | // Package iban contains utility functions for working with IBAN account numbers. 2 | package iban 3 | 4 | import ( 5 | "errors" 6 | "fmt" 7 | "log" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | // ErrInvalidIBAN is returned when an invalid IBAN number was received 13 | var ErrInvalidIBAN = errors.New("invalid IBAN number received") 14 | 15 | // IBAN represents an IBAN number, split up into its different parts. 16 | type IBAN struct { 17 | Number string // The full IBAN number 18 | CountryCode string // The country code of the IBAN 19 | Checksum string // The checksum of the IBAN 20 | BBAN string // The Basic Bank Account Number (BBAN) of the IBAN 21 | BankCode string // The bank code extracted from the IBAN 22 | } 23 | 24 | // NewIBAN creates a new instance of IBAN and checks if the IBAN number is valid. 25 | // If the IBAN is valid, it returns the IBAN struct with its different parts filled in. 26 | func NewIBAN(ibanNumber string) (IBAN, error) { 27 | isIBANValid, formattedIBANNumber, err := IsCorrectIban(ibanNumber, false) 28 | if err != nil || !isIBANValid { 29 | return IBAN{}, fmt.Errorf("%w: %v", ErrInvalidIBAN, err) 30 | } 31 | 32 | countryCode, checksum, bban := splitIbanUp(formattedIBANNumber) 33 | bankCode, _ := getBankCode(countryCode, formattedIBANNumber) 34 | 35 | return IBAN{ 36 | Number: formattedIBANNumber, 37 | CountryCode: countryCode, 38 | Checksum: checksum, 39 | BBAN: bban, 40 | BankCode: bankCode, 41 | }, nil 42 | } 43 | 44 | // getBankCode extracts the bank code from the IBAN based on the country configuration. 45 | func getBankCode(countryCode, ibanNumber string) (string, error) { 46 | if code, exists := countryList[countryCode]; exists { 47 | firstIndex := strings.Index(code.ibanFields, "b") 48 | lastIndex := strings.LastIndex(code.ibanFields, "b") 49 | if firstIndex != -1 && lastIndex != -1 { 50 | return ibanNumber[firstIndex : lastIndex+1], nil 51 | } 52 | } 53 | return "", errors.New("no bank code found") 54 | } 55 | 56 | type ibanCountry struct { 57 | country string // The country name 58 | chars int // The expected length of the IBAN for this country 59 | bbanFormat string // The format of the BBAN part of the IBAN 60 | code string // The country code 61 | ibanFields string // The fields of the IBAN (e.g., bank code, branch code) 62 | comment string // Additional comments about the IBAN format 63 | standardTreatment bool // Indicates if the country follows the standard treatment 64 | } 65 | 66 | // IsCorrectIban checks if the given IBAN number corresponds to the rules of a valid IBAN number. 67 | // It also returns a properly formatted IBAN number string. 68 | func IsCorrectIban(iban string, debug bool) (bool, string, error) { 69 | obscureIban := func(iban string) string { 70 | if len(iban) <= 6 { 71 | return iban 72 | } 73 | return iban[:2] + strings.Repeat("*", len(iban)-6) + iban[len(iban)-4:] 74 | } 75 | 76 | // Clean up and standardize the IBAN string 77 | iban = strings.ToUpper(strings.ReplaceAll(iban, " ", "")) 78 | if len(iban) < 15 { 79 | log.Printf("Incorrect IBAN string passed: %s", obscureIban(iban)) 80 | return false, "", fmt.Errorf("IBAN: incorrect IBAN string passed <%s>", obscureIban(iban)) 81 | } 82 | 83 | // Split the IBAN into its parts 84 | countryCode, checksum, bban := splitIbanUp(iban) 85 | ibanConfig, exists := countryList[countryCode] 86 | if !exists { 87 | log.Printf("Invalid IBAN country: IBAN %s has country code not in the list (%s)", obscureIban(iban), countryCode) 88 | return false, "", fmt.Errorf("IBAN: country <%s> is not in the list", countryCode) 89 | } 90 | 91 | // Check if the length matches the expected length for the country 92 | if ibanConfig.chars != len(iban) { 93 | log.Printf("Invalid IBAN length: IBAN %s length (%d) does not match configuration length (%d)", obscureIban(iban), len(iban), ibanConfig.chars) 94 | return false, "", fmt.Errorf("IBAN: length (%d) does not match configuration length (%d)", len(iban), ibanConfig.chars) 95 | } 96 | 97 | // Rearrange the IBAN for validation and convert characters to numbers 98 | rearrangedIban := rearrangeIBAN(countryCode, checksum, bban) 99 | convertedIban := convertCharToNumber(rearrangedIban) 100 | if calculateModulo(convertedIban) != 1 { 101 | return false, "", nil 102 | } 103 | 104 | return true, splitTo4(iban), nil 105 | } 106 | 107 | // splitIbanUp splits the IBAN into its country code, checksum, and BBAN parts. 108 | func splitIbanUp(iban string) (string, string, string) { 109 | return iban[:2], iban[2:4], iban[4:] 110 | } 111 | 112 | // splitTo4 splits the IBAN into groups of four characters for readability. 113 | func splitTo4(value string) string { 114 | var builder strings.Builder 115 | for i := 0; i < len(value); i += 4 { 116 | if i+4 < len(value) { 117 | builder.WriteString(value[i:i+4] + " ") 118 | } else { 119 | builder.WriteString(value[i:]) 120 | } 121 | } 122 | return builder.String() 123 | } 124 | 125 | // GetIbanChecksum returns the checksum of the given IBAN number. 126 | func GetIbanChecksum(iban string) (int, error) { 127 | // Clean up and standardize the IBAN string 128 | iban = strings.ToUpper(strings.ReplaceAll(iban, " ", "")) 129 | if len(iban) < 15 { 130 | log.Printf("Incorrect IBAN string passed for checksum calculation: %s", obscureIban(iban)) 131 | return -1, fmt.Errorf("IBAN: incorrect IBAN string passed <%s>", obscureIban(iban)) 132 | } 133 | 134 | // Rearrange the IBAN for checksum calculation 135 | countryCode, _, bban := splitIbanUp(iban) 136 | rearrangedIban := rearrangeIBAN(countryCode, "00", bban) 137 | convertedIban := convertCharToNumber(rearrangedIban) 138 | return 98 - calculateModulo(convertedIban), nil 139 | } 140 | 141 | // convertCharToNumber converts alphabetic characters in the IBAN to their corresponding numeric values. 142 | func convertCharToNumber(value string) string { 143 | var builder strings.Builder 144 | for _, item := range value { 145 | if item >= 'A' && item <= 'Z' { 146 | builder.WriteString(strconv.Itoa(int(item - 'A' + 10))) 147 | } else { 148 | builder.WriteRune(item) 149 | } 150 | } 151 | return builder.String() 152 | } 153 | 154 | // rearrangeIBAN rearranges the IBAN by moving the country code and checksum to the end. 155 | func rearrangeIBAN(countryCode, checksum, bban string) string { 156 | return bban + countryCode + checksum 157 | } 158 | 159 | // calculateModulo calculates the modulo 97 of the given IBAN number. 160 | func calculateModulo(iban string) int { 161 | for len(iban) > 9 { 162 | tempIBAN := iban[:9] 163 | value, err := strconv.Atoi(tempIBAN) 164 | if err != nil { 165 | return -1 166 | } 167 | rest := value % 97 168 | iban = strconv.Itoa(rest) + iban[9:] 169 | } 170 | 171 | value, err := strconv.Atoi(iban) 172 | if err != nil { 173 | return -1 174 | } 175 | 176 | return value % 97 177 | } 178 | 179 | // obscureIban obscures the middle part of an IBAN for logging purposes. 180 | func obscureIban(iban string) string { 181 | if len(iban) <= 6 { 182 | return iban 183 | } 184 | return iban[:2] + strings.Repeat("*", len(iban)-6) + iban[len(iban)-4:] 185 | } 186 | -------------------------------------------------------------------------------- /iban_test.go: -------------------------------------------------------------------------------- 1 | package iban 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | var validIBANTestNumbers = []struct { 10 | number string 11 | }{ 12 | {"EG210003700067100239218937900"}, 13 | } 14 | 15 | var invalidIBANTestNumbers = []struct { 16 | number string 17 | }{ 18 | {"LU12 3456 7890 1234 5678"}, 19 | } 20 | 21 | func TestValidIBAN(t *testing.T) { 22 | for _, ibanTestNumber := range validIBANTestNumbers { 23 | result, err := NewIBAN(ibanTestNumber.number) 24 | if err != nil || result == (IBAN{}) { 25 | t.Error("No object was created!") 26 | t.Log(err) 27 | } 28 | } 29 | } 30 | 31 | func TestInvalidIBAN(t *testing.T) { 32 | for _, ibanTestNumber := range invalidIBANTestNumbers { 33 | _, err := NewIBAN(ibanTestNumber.number) 34 | if err == nil { 35 | t.Error("No error was thrown for an invalid IBAN number!") 36 | } 37 | } 38 | } 39 | 40 | type IBANMessage struct { 41 | Country string `json:"country"` 42 | Code string `json:"code"` 43 | IBAN string `json:"iban"` 44 | } 45 | 46 | type IBANList struct { 47 | IBANs []IBANMessage `json:"ibans"` 48 | } 49 | 50 | // TestIsCorrectIban reads a list of IBANs from JSON and verifies each one with detailed logging. 51 | func TestIsCorrectIban(t *testing.T) { 52 | t.Log("Starting TestIsCorrectIban") 53 | 54 | // Attempt to open the JSON file 55 | t.Log("Attempting to open './data/iban.json'") 56 | file, err := os.Open("./data/iban.json") 57 | if err != nil { 58 | t.Fatalf("Error opening file: %v", err) 59 | } 60 | defer file.Close() 61 | t.Log("Successfully opened './data/iban.json'") 62 | 63 | // Decode JSON data 64 | t.Log("Decoding JSON data from file") 65 | var iList IBANList 66 | if err := json.NewDecoder(file).Decode(&iList); err != nil { 67 | t.Fatalf("Error unmarshalling data into the IBAN list: %v", err) 68 | } 69 | t.Log("Successfully decoded JSON data") 70 | 71 | // Test each IBAN entry 72 | for i, message := range iList.IBANs { 73 | //t.Logf("Testing IBAN: %s (Country: %s, Code: %s)", message.IBAN, message.Country, message.Code) 74 | ok, _, _ := IsCorrectIban(message.IBAN, false) 75 | if !ok { 76 | t.Errorf("Test case %d: Expected valid IBAN for %+v, but got invalid.", i+1, message) 77 | } 78 | } 79 | 80 | t.Log("Finished TestIsCorrectIban") 81 | } 82 | --------------------------------------------------------------------------------