Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
2026-10-20 Oleh Kobeliatskyi <@poputu>
* Fixed bank identifier extraction for SK, SM, SO, ST, SV, TL, TN, TR, UA, VA, VG and XK
* Fixed script/builder.rb skipping registry values after a cell that spans two lines

2026-04-10 Saša Jovanić <sasa@simplify.ba>
* Version 4.5.4

Expand Down
11 changes: 7 additions & 4 deletions script/builder.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'csv'

# Download: https://www.swift.com/swift-resource/11971/download
# or whatever the file path is on this page:
# https://www.swift.com/standards/data-standards/iban-international-bank-account-number
Expand Down Expand Up @@ -42,8 +44,9 @@ def create_specification(data)
end

def extract
data = File.readlines('./script/registry.txt').each_with_object([]) do |line, result|
data = line.force_encoding("iso-8859-1").split("\t").map { |e| e.strip }
rows = CSV.read('./script/registry.txt', col_sep: "\t", encoding: 'iso-8859-1')
data = rows.each_with_object([]) do |row, result|
data = row.map { |e| e.to_s.strip }
data[1..].each_with_index { |element, index| result[index] = { country_name: element } } if data.first == 'Name of country'
data[1..].each_with_index { |element, index| result[index][:code] = element } if data.first == 'IBAN prefix country code (ISO 3166)'
data[1..].each_with_index { |element, index| result[index][:sepa] = element == 'Yes' } if data.first == 'SEPA country'
Expand Down Expand Up @@ -76,10 +79,10 @@ def fix_ranges(ranges)
def type_to_range(type)
return '[A-Z0-9]' if type == 'c'
return '[0-9]' if type == 'n'

'[A-Z]'
end

def build_reqexp(format)
data = format.scan(/([0-9]+)!(.)/)
'^' + data.map { |(amount, type)| "#{type_to_range(type)}{#{amount}}" }.join + '$'
Expand Down
17 changes: 14 additions & 3 deletions script/iban_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -598,29 +598,31 @@ export const autogeneratedCountrySpecs = {
bban_regexp: '^[0-9]{5}[0-9]{8}[0-9]{2}$',
IBANRegistry: true,
SEPA: true,
branch_indentifier: '2-4',
bank_identifier: '0-1',
account_indentifier: '9-16',
bank_identifier: '0-4',
account_indentifier: '4-19',
},
SK: {
chars: 24,
bban_regexp: '^[0-9]{4}[0-9]{6}[0-9]{10}$',
IBANRegistry: true,
SEPA: true,
bank_identifier: '0-3',
},
SM: {
chars: 27,
bban_regexp: '^[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}$',
IBANRegistry: true,
SEPA: true,
branch_indentifier: '6-10',
bank_identifier: '1-5',
},
SO: {
chars: 23,
bban_regexp: '^[0-9]{4}[0-9]{3}[0-9]{12}$',
IBANRegistry: true,
SEPA: false,
branch_indentifier: '4-6',
bank_identifier: '0-3',
account_indentifier: '11-23',
},
ST: {
Expand All @@ -629,19 +631,22 @@ export const autogeneratedCountrySpecs = {
IBANRegistry: true,
SEPA: false,
branch_indentifier: '4-7',
bank_identifier: '0-3',
},
SV: {
chars: 28,
bban_regexp: '^[A-Z]{4}[0-9]{20}$',
IBANRegistry: true,
SEPA: false,
bank_identifier: '0-3',
account_indentifier: '8-28',
},
TL: {
chars: 23,
bban_regexp: '^[0-9]{3}[0-9]{14}[0-9]{2}$',
IBANRegistry: true,
SEPA: false,
bank_identifier: '0-2',
account_indentifier: '4-23',
},
TN: {
Expand All @@ -650,34 +655,39 @@ export const autogeneratedCountrySpecs = {
IBANRegistry: true,
SEPA: false,
branch_indentifier: '2-4',
bank_identifier: '0-1',
account_indentifier: '4-24',
},
TR: {
chars: 26,
bban_regexp: '^[0-9]{5}[0-9]{1}[A-Z0-9]{16}$',
IBANRegistry: true,
SEPA: false,
bank_identifier: '0-4',
account_indentifier: '0-0',
},
UA: {
chars: 29,
bban_regexp: '^[0-9]{6}[A-Z0-9]{19}$',
IBANRegistry: true,
SEPA: false,
bank_identifier: '0-5',
account_indentifier: '15-29',
},
VA: {
chars: 22,
bban_regexp: '^[0-9]{3}[0-9]{15}$',
IBANRegistry: true,
SEPA: true,
bank_identifier: '0-2',
account_indentifier: '7-22',
},
VG: {
chars: 24,
bban_regexp: '^[A-Z]{4}[0-9]{16}$',
IBANRegistry: true,
SEPA: false,
bank_identifier: '0-3',
account_indentifier: '8-24',
},
XK: {
Expand All @@ -686,6 +696,7 @@ export const autogeneratedCountrySpecs = {
IBANRegistry: true,
SEPA: false,
branch_indentifier: '2-3',
bank_identifier: '0-1',
account_indentifier: '4-20',
},
};
12 changes: 12 additions & 0 deletions src/ibantools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,7 @@ export const countrySpecs: CountryMapInternal = {
bban_validation_func: checkCzechAndSlovakBBAN,
IBANRegistry: true,
SEPA: true,
bank_identifier: '0-3',
},
SL: {},
SM: {
Expand All @@ -1714,6 +1715,7 @@ export const countrySpecs: CountryMapInternal = {
IBANRegistry: true,
SEPA: true,
branch_indentifier: '6-10',
bank_identifier: '1-5',
},
SN: {
chars: 28,
Expand All @@ -1724,6 +1726,7 @@ export const countrySpecs: CountryMapInternal = {
bban_regexp: '^[0-9]{19}$',
IBANRegistry: true,
branch_indentifier: '4-6',
bank_identifier: '0-3',
account_indentifier: '11-23',
},
SR: {},
Expand All @@ -1733,11 +1736,13 @@ export const countrySpecs: CountryMapInternal = {
bban_regexp: '^[0-9]{21}$',
IBANRegistry: true,
branch_indentifier: '4-7',
bank_identifier: '0-3',
},
SV: {
chars: 28,
bban_regexp: '^[A-Z]{4}[0-9]{20}$',
IBANRegistry: true,
bank_identifier: '0-3',
account_indentifier: '8-28',
},
SX: {},
Expand All @@ -1764,6 +1769,7 @@ export const countrySpecs: CountryMapInternal = {
chars: 23,
bban_regexp: '^[0-9]{19}$',
IBANRegistry: true,
bank_identifier: '0-2',
account_indentifier: '4-23',
},
TM: {},
Expand All @@ -1772,13 +1778,15 @@ export const countrySpecs: CountryMapInternal = {
bban_regexp: '^[0-9]{20}$',
IBANRegistry: true,
branch_indentifier: '2-4',
bank_identifier: '0-1',
account_indentifier: '4-24',
},
TO: {},
TR: {
chars: 26,
bban_regexp: '^[0-9]{5}[A-Z0-9]{17}$',
IBANRegistry: true,
bank_identifier: '0-4',
},
TT: {},
TV: {},
Expand All @@ -1788,6 +1796,7 @@ export const countrySpecs: CountryMapInternal = {
chars: 29,
bban_regexp: '^[0-9]{6}[A-Z0-9]{19}$',
IBANRegistry: true,
bank_identifier: '0-5',
account_indentifier: '15-29',
},
UG: {},
Expand All @@ -1800,6 +1809,7 @@ export const countrySpecs: CountryMapInternal = {
bban_regexp: '^[0-9]{18}',
IBANRegistry: true,
SEPA: true,
bank_identifier: '0-2',
account_indentifier: '7-22',
},
VC: {},
Expand All @@ -1808,6 +1818,7 @@ export const countrySpecs: CountryMapInternal = {
chars: 24,
bban_regexp: '^[A-Z0-9]{4}[0-9]{16}$',
IBANRegistry: true,
bank_identifier: '0-3',
account_indentifier: '8-24',
},
VI: {},
Expand All @@ -1824,6 +1835,7 @@ export const countrySpecs: CountryMapInternal = {
bban_regexp: '^[0-9]{16}$',
IBANRegistry: true,
branch_indentifier: '2-3',
bank_identifier: '0-1',
account_indentifier: '4-20',
},
YE: {
Expand Down
40 changes: 40 additions & 0 deletions test/ibantools_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,46 @@ describe('IBANTools', function() {
});
});

describe('When calling extractIBAN() with valid Ukrainian IBAN', function() {
var ext = iban.extractIBAN('UA213223130000026007233566001');
it('valid should be true', function() {
return expect(ext.valid).to.be.true;
});
it('BBAN should be 3223130000026007233566001', function() {
return expect(ext.bban).to.equal('3223130000026007233566001');
});
it('countryCode should be UA', function() {
return expect(ext.countryCode).to.equal('UA');
});
it('accountNumber should be 26007233566001', function() {
return expect(ext.accountNumber).to.equal('26007233566001');
});
it('bankIdentifier should be 322313', function() {
return expect(ext.bankIdentifier).to.equal('322313');
});
});

describe('When calling extractIBAN() with valid IBANs from SK, SM, SO, ST, SV, TL, TN, TR, UA, VA, VG and XK', function() {
[
['SK3112000000198742637541', '1200'],
['SM86U0322509800000000270100', '03225'],
['SO211000001001000100141', '1000'],
['ST68000100010051845310112', '0001'],
['SV62CENR00000000000000700025', 'CENR'],
['TL380080012345678910157', '008'],
['TN5910006035183598478831', '10'],
['TR330006100519786457841326', '00061'],
['UA213223130000026007233566001', '322313'],
['VA59001123000012345678', '001'],
['VG96VPVG0000012345678901', 'VPVG'],
['XK051212012345678906', '12'],
].forEach(function(example) {
it('bankIdentifier of ' + example[0] + ' should be ' + example[1], function() {
return expect(iban.extractIBAN(example[0]).bankIdentifier).to.equal(example[1]);
});
});
});

describe('When calling extractIBAN() with invalid IBAN', function() {
var ext = iban.extractIBAN('BR970036030510009795493P1');
it('valid should be false', function() {
Expand Down