Class: ISO::IBAN

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/iso/iban/no_autoload.rb,
lib/iso/iban/version.rb,
lib/iso/iban/invalid.rb,
lib/iso/iban/specification.rb

Overview

IBAN - ISO 13616-1

Usage

require 'iso/iban'
ISO::IBAN.valid?('CH35 1234 5987 6543 2109 A')       # => true
ISO::IBAN.validate('CH37 1234 5987 6543 2109 A')     # => [:invalid_checksum]
ISO::IBAN.generate('CH', '12345', '987')             # => #<ISO::IBAN CH76 1234 5000 0000 0098 7>
iban = ISO::IBAN.parse('CH35 1234 5987 6543 2109 A') # => #<ISO::IBAN CH35 1234 5987 6543 2109 A>
iban = ISO::IBAN.new('CH351234598765432109A')        # => #<ISO::IBAN CH35 1234 5987 6543 2109 A>
iban.formatted       # => "CH35 1234 5987 6543 2109 A"
iban.compact         # => "CH351234598765432109A"
iban.country         # => "CH"
iban.checksum_digits # => "35"
iban.bank_code       # => "12345"
iban.    # => "98765432109A"
iban.valid?          # => true
iban.validate        # => []

General IBAN Information

  • What is an IBAN?
    IBAN stands for International Bank Account Number. It is the ISO 13616 international standard for numbering bank accounts. In 2006, the International Organization for Standardization (ISO) designated SWIFT as the Registration Authority for ISO 13616.

  • Use
    The IBAN facilitates the communication and processing of cross-border transactions. It allows exchanging account identification details in a machine-readable form.

The ISO 13616 IBAN Standard

  • Structure
    The IBAN structure is defined in ISO 13616-1 and consists of a two-letter ISO 3166-1 country code, followed by two check digits and up to thirty alphanumeric characters for a BBAN (Basic Bank Account Number) which has a fixed length per country and, included within it, a bank identifier with a fixed position and a fixed length per country. The check digits are calculated based on the scheme defined in ISO/IEC 7064 (MOD97-10).

  • Terms and definitions

    • Bank identifier: The identifier that uniquely identifies the financial institution and, when appropriate, the branch of that financial institution servicing an account.

    • BBAN: basic bank account number: The identifier that uniquely identifies an individual account, at a specific financial institution, in a particular country. The BBAN includes a bank identifier of the financial institution servicing that account.

    • IBAN: international bank account number: The expanded version of the basic bank account number (BBAN), intended for use internationally. The IBAN uniquely identifies an individual account, at a specific financial institution, in a particular country.

  • Submitters
    Nationally-agreed, ISO13616-compliant IBAN formats are submitted to the registration authority exclusively by the National Standards Body or the National Central Bank of the country.

Defined Under Namespace

Classes: Invalid, Specification

Constant Summary

Version =
Note:

require 'iso/iban' loads the version.

The version of the sorting gem.

Gem::Version.new("0.1.0")
CharacterCodes =

Character code translation used to convert an IBAN into its numeric (digits-only) form

Hash[('0'..'9').zip('0'..'9')+('a'..'z').zip(10..35)+('A'..'Z').zip(10..35)]
UpperAlpha =

All uppercase letters

[*'A'..'Z']
LowerAlpha =

All lowercase letters

[*'a'..'z']
Digits =

All digits

[*'0'..'9']
AlphaNumeric =

All uppercase letters, lowercase letters and digits

[*'A'..'Z', *'a'..'z', *'0'..'9']

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (IBAN) initialize(iban)

Returns a new instance of IBAN

Parameters:

  • iban (String)

    The IBAN number, must be in compact form. Use ISO::IBAN::parse for formatted IBANs.

Raises:

  • (ArgumentError)


280
281
282
283
284
285
286
# File 'lib/iso/iban/no_autoload.rb', line 280

def initialize(iban)
  raise ArgumentError, "String expected for iban, but got #{iban.class}" unless iban.is_a?(String)

  @compact       = iban.b
  @country       = iban[0,2]
  @specification = self.class.specification(@country, nil)
end

Instance Attribute Details

- (String) compact (readonly)

Returns The standard form of the IBAN for machine communication, without spaces, encoded in Encoding::BINARY.

Returns:

  • (String)

    The standard form of the IBAN for machine communication, without spaces, encoded in Encoding::BINARY.



270
271
272
# File 'lib/iso/iban/no_autoload.rb', line 270

def compact
  @compact
end

- (String) country (readonly)

Returns The ISO-3166 2-letter country code (first and second character).

Returns:

  • (String)

    The ISO-3166 2-letter country code (first and second character).



273
274
275
# File 'lib/iso/iban/no_autoload.rb', line 273

def country
  @country
end

- (ISO::IBAN::Specification) specification (readonly)

Returns The specification for this IBAN (determined by its country).

Returns:



276
277
278
# File 'lib/iso/iban/no_autoload.rb', line 276

def specification
  @specification
end

Class Method Details

+ (Object) generate(country, *components)

Note:

generate will pad all segments with zeros, which means it will generate invalid IBANs if you provide too short segments which are alphabetic only.
For example, ISO::IBAN.generate('BG', 'A', '2', 'C') generates an invalid IBAN.

Generate an IBAN from country code and components, automatically filling in the checksum.

Examples:

Generate an IBAN for UBS Switzerland with account number '12345'

ISO::IBAN.generate('CH', '216', '12345') # => #<ISO::IBAN CH92 0021 6000 0000 1234 5>

Parameters:

  • country (String)

    The ISO-3166 2-letter country code.



218
219
220
221
222
223
224
225
# File 'lib/iso/iban/no_autoload.rb', line 218

def self.generate(country, *components)
  spec      = specification(country)
  justified = spec.component_lengths.zip(components).map { |length, component| component.rjust(length, "0") }
  iban      = new(country+'??'+justified.join(''))
  iban.update_checksum!

  iban
end

+ (self) load_specifications(spec_file = nil)

Note:

Using require 'iso/iban' will automatically invoke this method. If you do not wish this behavior, require 'iso/iban/no_autoload' instead.

Load the IBAN specifications file, which determines how the IBAN for any given country looks.

It will use the following sources in this order (first one which exists wins)

  • Path passed as spec_file parameter

  • Path provided by the env variable IBAN_SPECIFICATIONS

  • The file ../data/iso-iban/specs.yaml relative to the lib dir

  • The Gem datadir path

Parameters:

  • spec_file (String) (defaults to: nil)

    Override the default specifications file path.

Returns:

  • (self)


115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/iso/iban/no_autoload.rb', line 115

def self.load_specifications(spec_file=nil)
  if spec_file then
    # do nothing
  elsif ENV['IBAN_SPECIFICATIONS'] then
    spec_file = ENV['IBAN_SPECIFICATIONS']
  else
    spec_file = File.expand_path('../../../../data/iso-iban/specs.yaml', __FILE__)
    if !File.file?(spec_file) && defined?(Gem) && Gem.datadir('iso-iban')
      spec_file = Gem.datadir('iso-iban')+'/specs.yaml'
    end
  end

  if spec_file && File.file?(spec_file)
    @specifications = ISO::IBAN::Specification.load_yaml(spec_file)
  elsif spec_file
    raise "Could not load IBAN specifications, specs file #{spec_file.inspect} does not exist or can't be read."
  else
    raise "Could not load IBAN specifications, no specs file found."
  end

  self
end

+ (String) numerify(string)

Converts a String into its digits-only form, i.e. all characters a-z are replaced with their corresponding digit sequences, according to the IBAN specification.

Parameters:

  • string (String)

    The string to convert into its numeric form.

Returns:

  • (String)

    The string in its numeric, digits-only form.



261
262
263
264
265
266
267
# File 'lib/iso/iban/no_autoload.rb', line 261

def self.numerify(string)
  string.downcase.gsub(/\D/) { |char|
    CharacterCodes.fetch(char) {
      raise ArgumentError, "The string contains an invalid character #{char.inspect}"
    }
  }.to_i
end

+ (ISO::IBAN) parse(iban_number)

Returns An IBAN instance representing the passed IBAN number.

Parameters:

  • iban_number (String)

    The IBAN in either compact or human readable form.

Returns:

  • (ISO::IBAN)

    An IBAN instance representing the passed IBAN number.



201
202
203
# File 'lib/iso/iban/no_autoload.rb', line 201

def self.parse(iban_number)
  new(strip(iban_number))
end

+ (ISO::IBAN) parse!(iban_number)

Like ISO::IBAN.parse, but raises an ISO::IBAN::Invalid exception if the IBAN is invalid.

Parameters:

  • iban_number (String)

    The IBAN in either compact or human readable form.

Returns:

  • (ISO::IBAN)

    An IBAN instance representing the passed IBAN number.

Raises:



189
190
191
192
193
194
# File 'lib/iso/iban/no_autoload.rb', line 189

def self.parse!(iban_number)
  iban   = parse(iban_number)
  raise Invalid.new(iban) unless iban.valid?

  iban
end

+ (ISO::IBAN) random(*countries)

Returns A random, valid IBAN.

Parameters:

  • countries (String)

    A list of 2 letter country codes. If empty, all countries in ISO::IBAN::specifications are used.

Returns:



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/iso/iban/no_autoload.rb', line 231

def self.random(*countries)
  countries = specifications.keys if countries.empty?
  country   = countries.sample
     = specification(country).iban_structure.scan(/([A-Z]+)|(\d+)(!?)([nac])/).map { |exact, length, fixed, code|
    if exact
      exact
    elsif code == 'a'
      Array.new(length.to_i) { UpperAlpha.sample }.join('')
    elsif code == 'c'
      Array.new(length.to_i) { AlphaNumeric.sample }.join('')
    elsif code == 'e'
      ' '*length.to_i
    elsif code == 'n'
      Array.new(length.to_i) { Digits.sample }.join('')
    end
  }.join('')
  [2,2] = '??'
  iban = new()
  iban.update_checksum!

  iban
end

+ (ISO::IBAN::Specification) specification(a2_country_code, *default, &default_block)

Returns The specification for the given country.

Parameters:

  • a2_country_code (String)

    The country (ISO3166 2-letter), e.g. 'CH' or 'DE'.

Returns:



149
150
151
# File 'lib/iso/iban/no_autoload.rb', line 149

def self.specification(a2_country_code, *default, &default_block)
  specifications.fetch(a2_country_code, *default, &default_block)
end

+ (Hash<String => ISO::IBAN::Specification>) specifications

Returns A hash with the country (ISO3166 2-letter) as key and the specification for that country as value.

Returns:



140
141
142
# File 'lib/iso/iban/no_autoload.rb', line 140

def self.specifications
  @specifications || raise("No specifications have been loaded yet - Check the docs for ISO::IBAN::load_specifications.")
end

+ (String) strip(iban)

Returns The IBAN in compact form, all whitespace and dashes stripped.

Parameters:

  • iban (String)

    The IBAN in either compact or human readable form.

Returns:

  • (String)

    The IBAN in compact form, all whitespace and dashes stripped.



178
179
180
# File 'lib/iso/iban/no_autoload.rb', line 178

def self.strip(iban)
  iban.delete("\n\r\t -")
end

+ (true, false) valid?(iban)

Returns Whether the IBAN is valid.
See #validate for details.

Parameters:

  • iban (String)

    An IBAN number, either in compact or human format.

Returns:

  • (true, false)

    Whether the IBAN is valid.
    See #validate for details.



159
160
161
# File 'lib/iso/iban/no_autoload.rb', line 159

def self.valid?(iban)
  parse(iban).valid?
end

+ (Array<Symbol>) validate(iban)

Returns An array with a code of all validation errors, empty if valid.
See #validate for details.

Parameters:

  • iban (String)

    An IBAN number, either in compact or human format.

Returns:

  • (Array<Symbol>)

    An array with a code of all validation errors, empty if valid.
    See #validate for details.



169
170
171
# File 'lib/iso/iban/no_autoload.rb', line 169

def self.validate(iban)
  parse(iban).validate
end

Instance Method Details

- (-1, ...) <=>(other)

See Object#<=>

Returns:

  • (-1, 0, 1, nil)


425
426
427
# File 'lib/iso/iban/no_autoload.rb', line 425

def <=>(other)
  other.respond_to?(:compact) ? @compact <=> other.compact : nil
end

- (String) account_code

Returns The account code part of the IBAN.

Returns:

  • (String)

    The account code part of the IBAN.



373
374
375
# File 'lib/iso/iban/no_autoload.rb', line 373

def 
  @compact[((@specification.branch_position_to || @specification.bank_position_to || 3)+1)..-1]
end

- (String?) bank_code

Returns The bank code part of the IBAN, nil if not applicable.

Returns:

  • (String, nil)

    The bank code part of the IBAN, nil if not applicable.



355
356
357
358
359
360
361
# File 'lib/iso/iban/no_autoload.rb', line 355

def bank_code
  if @specification && @specification.bank_position_from && @specification.bank_position_to
    @compact[@specification.bank_position_from..@specification.bank_position_to]
  else
    nil
  end
end

- (String) bban

Returns The BBAN of the IBAN (everything except the country code and check digits).

Returns:

  • (String)

    The BBAN of the IBAN (everything except the country code and check digits).



350
351
352
# File 'lib/iso/iban/no_autoload.rb', line 350

def bban
  @compact[4..-1]
end

- (String?) branch_code

Returns The branch code part of the IBAN, nil if not applicable.

Returns:

  • (String, nil)

    The branch code part of the IBAN, nil if not applicable.



364
365
366
367
368
369
370
# File 'lib/iso/iban/no_autoload.rb', line 364

def branch_code
  if @specification && @specification.branch_position_from && @specification.branch_position_to
    @compact[@specification.branch_position_from..@specification.branch_position_to]
  else
    nil
  end
end

- (String) calculated_check_digits

Returns The check-digits as calculated from the IBAN.

Returns:

  • (String)

    The check-digits as calculated from the IBAN.



442
443
444
# File 'lib/iso/iban/no_autoload.rb', line 442

def calculated_check_digits
  "%02d" % (98-(self.class.numerify(bban+@country)*100)%97)
end

- (String) checksum_digits

Returns The checksum digits in the IBAN (character 3 & 4).

Returns:

  • (String)

    The checksum digits in the IBAN (character 3 & 4).



345
346
347
# File 'lib/iso/iban/no_autoload.rb', line 345

def checksum_digits
  @compact[2,2]
end

- (true, false) eql?(other)

Returns Whether two ISO::IBANs are equal. Comparison is based on class and IBAN number

Returns:

  • (true, false)

    Whether two ISO::IBANs are equal. Comparison is based on class and IBAN number



449
450
451
# File 'lib/iso/iban/no_autoload.rb', line 449

def eql?(other)
  self.class.equal?(other.class) && self == other
end

- (String) formatted

Returns The IBAN in its formatted form, which is more human readable than the compact form.

Examples:

Formatted IBAN


ISO::IBAN.new('CH')

Returns:

  • (String)

    The IBAN in its formatted form, which is more human readable than the compact form.



293
294
295
# File 'lib/iso/iban/no_autoload.rb', line 293

def formatted
  @_formatted ||= @compact.gsub(/.{4}(?=.)/, '\0 ')
end

- (Integer) hash

Returns A hash value, see Object#hash

Returns:

  • (Integer)

    A hash value, see Object#hash



455
456
457
# File 'lib/iso/iban/no_autoload.rb', line 455

def hash
  [self.class, @compact].hash
end

- (Object) inspect

See Object#inspect



460
461
462
# File 'lib/iso/iban/no_autoload.rb', line 460

def inspect
  sprintf "#<%p %s>", self.class, formatted
end

- (Array) invalid_characters(input_encoding = nil)

Returns An Array with all invalid characters.

Examples:

invalid = "hägar"
invalid.encoding # => #<Encoding:UTF-8>
ISO::IBAN.new(invalid).invalid_characters          # => ["\xC3", "\xA4"]
ISO::IBAN.new(invalid).invalid_characters('utf-8') # => ["ä"]

Parameters:

  • input_encoding (String, Encoding, nil) (defaults to: nil)

    ISO::IBAN::new interprets the passed IBAN as binary. If you got the IBAN from a source which is not binary, you should provide that encoding. Otherwise an invalid character may be split into multiple bytes.

Returns:

  • (Array)

    An Array with all invalid characters.



389
390
391
392
393
# File 'lib/iso/iban/no_autoload.rb', line 389

def invalid_characters(input_encoding=nil)
  iban = input_encoding ? @compact.dup.force_encoding(input_encoding) : @compact

  iban.gsub(/[A-Z0-9?]*/i, '').chars.uniq
end

- (Integer?) numeric

Returns IBAN in its numeric form, i.e. all characters a-z are replaced with their corresponding digit sequences.
Will return nil if the IBAN is shorter than 5 characters (which makes it invalid).

Returns:

  • (Integer, nil)

    IBAN in its numeric form, i.e. all characters a-z are replaced with their corresponding digit sequences.
    Will return nil if the IBAN is shorter than 5 characters (which makes it invalid).



301
302
303
# File 'lib/iso/iban/no_autoload.rb', line 301

def numeric
  @compact.size < 5 ? nil : self.class.numerify(@compact[4..-1]+@compact[0,4])
end

- (Array) to_a

Note:

This method is experimental. It might change or be removed in future versions!

Returns The individual IBAN components as defined by the SWIFT specification. An empty array if this IBAN does not have a specification.

Returns:

  • (Array)

    The individual IBAN components as defined by the SWIFT specification. An empty array if this IBAN does not have a specification.



475
476
477
478
479
# File 'lib/iso/iban/no_autoload.rb', line 475

def to_a
  @_components ||= @specification ? @compact.match(@specification.iban_regex).captures : []

  @_components.dup
end

- (String) to_s

Returns The compact form of the IBAN as a String.

Returns:

  • (String)

    The compact form of the IBAN as a String.



465
466
467
# File 'lib/iso/iban/no_autoload.rb', line 465

def to_s
  @compact.dup
end

- (self) update_checksum!

Requires that the checksum digits were left as '??', replaces them with the proper checksum.

Returns:

  • (self)


433
434
435
436
437
438
439
# File 'lib/iso/iban/no_autoload.rb', line 433

def update_checksum!
  raise "Checksum digit placeholders missing" unless @compact[2,2] == '??'

  @compact[2,2] = calculated_check_digits

  self
end

- (true, false) valid?

Returns Whether the IBAN is valid. See #validate for details.

Returns:

  • (true, false)

    Whether the IBAN is valid. See #validate for details.



308
309
310
# File 'lib/iso/iban/no_autoload.rb', line 308

def valid?
  valid_country? && valid_checksum? && valid_length? && valid_format?
end

- (true, false) valid_characters?

Returns Whether IBAN consists only of valid characters.

Returns:

  • (true, false)

    Whether IBAN consists only of valid characters.



396
397
398
# File 'lib/iso/iban/no_autoload.rb', line 396

def valid_characters?
  @compact =~ /\A[A-Z]{2}(?:\d\d|\?\?)[A-Z0-9]*\z/in ? true : false
end

- (true, false) valid_checksum?

Returns Whether the checksum of the IBAN is valid.

Returns:

  • (true, false)

    Whether the checksum of the IBAN is valid.



416
417
418
419
420
# File 'lib/iso/iban/no_autoload.rb', line 416

def valid_checksum?
  numerified = numeric()

  numerified && (numerified % 97 == 1)
end

- (true, false) valid_country?

Returns Whether the country of the IBAN is valid.

Returns:

  • (true, false)

    Whether the country of the IBAN is valid.



401
402
403
# File 'lib/iso/iban/no_autoload.rb', line 401

def valid_country?
  @specification ? true : false
end

- (true, false) valid_format?

Returns Whether the format of the IBAN is valid.

Returns:

  • (true, false)

    Whether the format of the IBAN is valid.



406
407
408
# File 'lib/iso/iban/no_autoload.rb', line 406

def valid_format?
  @specification && @specification.iban_regex =~ @compact ? true : false
end

- (true, false) valid_length?

Returns Whether the length of the IBAN is valid.

Returns:

  • (true, false)

    Whether the length of the IBAN is valid.



411
412
413
# File 'lib/iso/iban/no_autoload.rb', line 411

def valid_length?
  @specification && @compact.size == @specification.iban_length ? true : false
end

- (Array<Symbol>) validate

Note:

The class method validate uses parse, which means it will strip whitespace and dashes from the IBAN.
#initialize on the other hand expects the IBAN in compact format and will not strip those characters.

Error codes:

  • :invalid_characters

  • :invalid_country

  • :invalid_checksum

  • :invalid_length

  • :invalid_format

Invalid characters means that the IBAN contains characters which are not in the set of A-Za-z0-9. See #invalid_characters.
Invalid country means the country is unknown (character 1 & 2 in the IBAN).
Invalid checksum means the two check digits (character 3 & 4 in the IBAN).
Invalid length means the IBAN does not comply with the length specified for the country of that IBAN.
Invalid format means the IBAN does not comply with the format specified for the country of that IBAN.

Returns:

  • (Array<Symbol>)

    An array with a code of all validation errors, empty if valid.



333
334
335
336
337
338
339
340
341
342
# File 'lib/iso/iban/no_autoload.rb', line 333

def validate
  errors   = []
  errors << :invalid_characters unless valid_characters?
  errors << :invalid_country    unless valid_country?
  errors << :invalid_checksum   unless valid_characters? && valid_checksum?
  errors << :invalid_length     unless valid_length?
  errors << :invalid_format     unless valid_format?

  errors
end