#!/usr/bin/perl

use strict;
use warnings;

my $IBAN;
my @test = ('AD1200012030200359100100',
'AT611904300234573201',
'BE68539007547034',
'ES9121000418450200051332',
'NL91ABNA0417164300',
'IE29AIBK93115212345678',
'IS140159260076545510730339',
'IT60X0542811101000000123456',
'GR1601101250000000012300695',
'LV95HABA0055123456789',
'LI21088100002324013AA',
'LT827300010002027432',
'LU280019400644750000',
'NO9386011117947',
'PL61109010140000071219812874',
'PT50000201231234567890154',
'FR1420041010050500013M02606',
'SE3550000000054910000003',
'DE89370400440532013000',
'SI56191000000123438',
'CH9300762011623852957',
'FI2112345600000785',
'GB29NWBK60161331926819',
'DK5000400440116243',
'CZ6508000000192000145399',
'TN5914207207100707129648',
'DE80700100800593232807',
'DE64700934000000086584');

foreach (@test)
  {
  if(check_iban($_))
    { print "The IBAN: $_ is correct\n"; }
  else
    { print "The IBAN: $_ is WRONG\n"; }
  }

sub check_swift #($swift)
  {
  my $swift = shift;
  $swift =~ s/[^A-Za-z0-9]//g;
  return 1 if($swift =~ m/^([a-zA-Z]){4}([a-zA-Z]){2}([0-9a-zA-Z]){2}([0-9a-zA-Z]{3})?$/);
  return 0;
  }


sub check_iban #($IBAN)
  {
  # Ueberpruefen einer IBAN: Neuberechnung der Pruefsumme und Vergleich
  # Kann auch zum Berechnen der IBAN-Pruefsumme verwendet werden
  # Info siehe unter http://www.iban.de/iban-pruefsumme.html

  # Laenge der IBAN in den einzelnen Laendern
  my %countrycodelengths = 
    ( "AL" =>  28, "AD" =>  24, "AT" =>  20, "AZ" =>  28,
      "BE" =>  16, "BH" =>  22, "BA" =>  20, "BR" =>  29,
      "BG" =>  22, "CR" =>  21, "HR" =>  21, "CY" =>  28,
	  "CZ" =>  24, "DK" =>  18, "DO" =>  28, "EE" =>  20,
	  "FO" =>  18, "FI" =>  18, "FR" =>  27, "GE" =>  22,
	  "DE" =>  22, "GI" =>  23, "GR" =>  27, "GL" =>  18,
	  "GT" =>  28, "HU" =>  28, "IS" =>  26, "IE" =>  22,
	  "IL" =>  23, "IT" =>  27, "KZ" =>  20, "KW" =>  30,
	  "LV" =>  21, "LB" =>  28, "LI" =>  21, "LT" =>  20,
	  "LU" =>  20, "MK" =>  19, "MT" =>  31, "MR" =>  27,
	  "MU" =>  30, "MC" =>  27, "MD" =>  24, "ME" =>  22,
	  "NL" =>  18, "NO" =>  15, "PK" =>  24, "PS" =>  29,
	  "PL" =>  28, "PT" =>  25, "RO" =>  24, "SM" =>  27,
	  "SA" =>  24, "RS" =>  22, "SK" =>  24, "SI" =>  19,
	  "ES" =>  24, "SE" =>  24, "CH" =>  21, "TN" =>  24,
	  "TR" =>  26, "AE" =>  23, "GB" =>  22, "VG" =>  24 ) ;

  # IBAN ist Argument
  my $IBAN = shift;

  # Hilfsvariablen
  my $string = '';
  my $C_IBAN = '';
  my $num = 0;

  # Fuellzeichen entfernen
  $IBAN =~ tr/[a-z]/[A-Z]/;
  $IBAN =~ s/[^A-Z0-9]//g;

  # Laendercode und Laenge pruefen
  return 0 if (not exists $countrycodelengths{substr($IBAN, 0, 2)});
  return 0 if (length($IBAN) != $countrycodelengths{substr($IBAN, 0, 2)});

  # Buchstaben konvertieren ('A' = 10, 'B' = 11, usw.)
  # --> IBAN-Codierung = ASCII-Codierung - 55 (z. B. 'A': ASCII 65 --> IBAN 10)  
  $string = $IBAN;
  $string =~ s/([A-Z])/ord($1) - 55/eg ;

  # Pruefsumme loeschen und ans Ende "00" setzen
  my $str = substr($string,6) . substr($string,0,4) . "00";

  # succesive Division mod 97
  while(length($str) > 0)
    {
    if($num != 0) { $num .= substr($str,0,1); }
    else { $num = substr($str,0,1); }
    $str = substr($str,1);
    $num = $num % 97;
    }

  # Divisions-Rest berechnen, Pruefsumme einsetzen
  $num = 98 - $num;
  if(length($num) < 2){$num = "0" . $num;} # zweistellig machen
  $C_IBAN = substr($IBAN,0,2) . $num . substr($IBAN,4);
  $C_IBAN =~ tr/[a-z]/[A-Z]/;

  # Check IBAN
  return 0 if($IBAN ne $C_IBAN);
  return 1; 
  }

