Update all new Tasks

This commit is contained in:
Ingy döt Net 2015-02-20 09:02:09 -05:00
parent 00a190b0a6
commit 91df62d461
5697 changed files with 93386 additions and 804 deletions

8
Task/IBAN/00DESCRIPTION Normal file
View file

@ -0,0 +1,8 @@
{{wikipedia}}
The [[wp:International_Bank_Account_Number|International Bank Account Number (IBAN)]] is an internationally agreed means of identifying bank accounts across national borders with a reduced risk of propagating [[wp:Transcription_error|transcription errors]]. <br>
The IBAN consists of up to 34 alphanumeric characters: first the two-letter ISO 3166-1 alpha-2 country code, then two check digits, and finally a country-specific Basic Bank Account Number (BBAN). <br>
The check digits enable a sanity check of the bank account number to confirm its integrity even before submitting a transaction.
The task here is to validate the following fictitious IBAN: <tt>GB82 WEST 1234 5698 7654 32</tt>.
Details of the algorithm can be found on the Wikipedia page.

2
Task/IBAN/00META.yaml Normal file
View file

@ -0,0 +1,2 @@
---
note: Checksums

3
Task/IBAN/Ada/iban-1.ada Normal file
View file

@ -0,0 +1,3 @@
package Iban_Code is
function Is_Legal(Iban : String) return Boolean;
end Iban_Code;

88
Task/IBAN/Ada/iban-2.ada Normal file
View file

@ -0,0 +1,88 @@
with Ada.Characters.Handling; use Ada.Characters.Handling;
with Ada.Containers.Hashed_Maps;
with Ada.Strings.Hash;
package body Iban_Code is
subtype Nation is String (1..2);
package String_Integer is new Ada.Containers.Hashed_Maps
(Nation, Integer, Ada.Strings.Hash, Equivalent_Keys => "=");
Nations : String_Integer.Map;
function Is_Legal(Iban : String) return Boolean
is
Temp : String(Iban'Range) := (others => ' ');
Count : Integer;
Ch : Character;
Num : Integer := 0;
begin
-- remove blank spaces and check characters
Count := Temp'First;
for I in Iban'Range loop
case Iban(I) is
when ' ' => null;
when 'a'..'z' =>
Temp(Count) := To_Upper(Iban(I));
Count := Count + 1;
when 'A'..'Z'|'0'..'9' =>
Temp(Count) := Iban(I);
Count := Count + 1;
when others => return False;
end case;
end loop;
-- check nation code and length
if not Nations.Contains (Temp(1..2)) or else
Nations.Element (Temp(1..2))/= Count - 1 then
return False;
end if;
-- move the 4 initial characters to the end
Temp(Temp'First..Count-1) := Temp(5..Count-1) & Temp(Temp'First..4);
-- compute remainder modulo 97
for I in Temp'First..Count-1 loop
Ch := Temp(I);
if Ch in '0'..'9' then
Num := Integer'Value(Integer'Image(Num) & Ch) mod 97;
else
Num := (Num * 100 +
(Character'Pos(Ch) - Character'Pos('A') + 10)) mod 97;
end if;
end loop;
return Num = 1;
end Is_Legal;
begin
Nations.insert("AL", 28); Nations.insert("AD", 24);
Nations.insert("AT", 20); Nations.insert("AZ", 28);
Nations.insert("BE", 16); Nations.insert("BH", 22);
Nations.insert("BA", 20); Nations.insert("BR", 29);
Nations.insert("BG", 22); Nations.insert("CR", 21);
Nations.insert("HR", 21); Nations.insert("CY", 28);
Nations.insert("CZ", 24); Nations.insert("DK", 18);
Nations.insert("DO", 28); Nations.insert("EE", 20);
Nations.insert("FO", 18); Nations.insert("FI", 18);
Nations.insert("FR", 27); Nations.insert("GE", 22);
Nations.insert("DE", 22); Nations.insert("GI", 23);
Nations.insert("GR", 27); Nations.insert("GL", 18);
Nations.insert("GT", 28); Nations.insert("HU", 28);
Nations.insert("IS", 26); Nations.insert("IE", 22);
Nations.insert("IL", 23); Nations.insert("IT", 27);
Nations.insert("KZ", 20); Nations.insert("KW", 30);
Nations.insert("LV", 21); Nations.insert("LB", 28);
Nations.insert("LI", 21); Nations.insert("LT", 20);
Nations.insert("LU", 20); Nations.insert("MK", 19);
Nations.insert("MT", 31); Nations.insert("MR", 27);
Nations.insert("MU", 30); Nations.insert("MC", 27);
Nations.insert("MD", 24); Nations.insert("ME", 22);
Nations.insert("NL", 18); Nations.insert("NO", 15);
Nations.insert("PK", 24); Nations.insert("PS", 29);
Nations.insert("PL", 28); Nations.insert("PT", 25);
Nations.insert("RO", 24); Nations.insert("SM", 27);
Nations.insert("SA", 24); Nations.insert("RS", 22);
Nations.insert("SK", 24); Nations.insert("SI", 19);
Nations.insert("ES", 24); Nations.insert("SE", 24);
Nations.insert("CH", 21); Nations.insert("TN", 24);
Nations.insert("TR", 26); Nations.insert("AE", 23);
Nations.insert("GB", 22); Nations.insert("VG", 24);
end Iban_Code;

21
Task/IBAN/Ada/iban-3.ada Normal file
View file

@ -0,0 +1,21 @@
with Ada.Text_Io; use Ada.Text_Io;
with Iban_Code;
procedure Check_Iban is
procedure Check(Iban : String) is
begin
if Iban_Code.Is_Legal(Iban) then
Put_Line(Iban & " is valid.");
else
Put_Line(Iban & " is not valid.");
end if;
end Check;
begin
Check("GB82 WEST 1234 5698 7654 32");
Check("GB82WEST12345698765432");
Check("gb82 west 1234 5698 7654 32");
Check("GB82 TEST 1234 5698 7654 32");
Check("GB82 WEST 1243 5698 7654 32");
end Check_Iban;

View file

@ -0,0 +1,43 @@
IBANs := ["GB82 WEST 1234 5698 7654 32"
, "gb82 WEST 1234 5698 7654 32"
, "GB82WEST12345698765432"
, "GB82 WEST 234 5698 7654 32"
, "GB82 WEST 1234 5698 7654 33"
, "AE82 WEST 1234 5698 7654 32"]
for k, v in IBANs
Output .= v " is" (ValidIBAN(v) ? "" : " not") " valid.`n"
MsgBox, % Output
ValidIBAN(n) {
static CC := {AL:28, AD:24, AT:20, AZ:28, BH:22, BE:16, 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
, JO:30, 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, QA:29, 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}
StringReplace, n, n, % A_Space,, A
;Check that the total IBAN length is correct as per the country
if (StrLen(n) != CC[SubStr(n, 1, 2)])
return false
StringUpper, n, n
;Move the four initial characters to the end of the string
n := SubStr(n, 5) SubStr(n, 1, 4)
;Replace each letter in the string with two digits
Loop, Parse, n
{
if A_LoopField is alpha
nn .= Asc(A_LoopField) - 55
else
nn .= A_LoopField
}
return Mod97(nn) = 1
}
Mod97(a) {
while a {
rem := Mod(rem SubStr(a, 1, 15), 97)
a := SubStr(a, 16)
}
return rem
}

View file

@ -0,0 +1,93 @@
REM Used the following as official standard:
REM http://www.cnb.cz/cs/platebni_styk/iban/download/EBS204.pdf
REM Pairs of ISO 3166 country code & expected IBAN length for this country
COULEN$="AL28 AD24 AT20 AZ28 BE16 BH22 BA20 BR29 BG22 CR21 HR21 CY28 CZ24 DK18 DO28 EE20 "+\
\ "FO18 FI18 FR27 GE22 DE22 GI23 GR27 GL18 GT28 HU28 IS26 IE22 IL23 IT27 KZ20 KW30 "+\
\ "LV21 LB28 LI21 LT20 LU20 MK19 MT31 MR27 MU30 MC27 MD24 ME22 NL18 NO15 PK24 PS29 "+\
\ "PL28 PT25 RO24 SM27 SA24 RS22 SK24 SI19 ES24 SE24 CH21 TN24 TR26 AE23 GB22 VG24"
PROCIBANcheck("GB82 WEST 1234 5698 7654 32"):REM Paper IBAN notation (with the spaces)
PROCIBANcheck("GB82WEST12345698765432") :REM Digital IBAN notation (without the spaces)
PROCIBANcheck("gb82 west 1234 5698 7654 32")
PROCIBANcheck("GB82 TEST 1234 5698 7654 32")
PROCIBANcheck("GR16 0110 1250 0000 0001 2300 695")
PROCIBANcheck("GB29 NWBK 6016 1331 9268 19")
PROCIBANcheck("SA03 8000 0000 6080 1016 7519")
PROCIBANcheck("CH93 0076 2011 6238 5295 7")
PROCIBANcheck("IL62 0108 0000 0009 9999 999")
PROCIBANcheck("IL62-0108-0000-0009-9999-999")
PROCIBANcheck("US12 3456 7890 0987 6543 210")
PROCIBANcheck("GR16 0110 1250 0000 0001 2300 695X")
END
DEF PROCIBANcheck(iban$)
LOCAL err$,i%,match%,explen%,digiban$,tmpiban$,bignum$,c%,kk%
REM Search for country code and fetch expected length
i%=1:explen%=0
WHILE explen%=0 AND i%<LENCOULEN$
IF LEFT$(iban$,2)=MID$(COULEN$,i%,2) explen%=VALMID$(COULEN$,i%+2,2)
i%+=5
ENDWHILE
match%=explen%>0
REM Continue if country code found
IF match% THEN
REM Remove space = convert to digital IBAN
digiban$=""
FOR i%=1TOLENiban$
IF MID$(iban$,i%,1)>" " digiban$+=MID$(iban$,i%,1)
NEXT
REM Compare length with expected length
match%=explen%=LENdigiban$
REM Continue if length is correct
IF match% THEN
REM Create temporary string with country code appended
tmpiban$=MID$(digiban$,5)+MID$(digiban$,1,2)
REM Make big number, replacing letters by numbers using next conversion table: A=10 ... Z=35
bignum$=""
FOR i%=1TOLENtmpiban$
c%=ASCMID$(tmpiban$,i%,1)
IF c%>57 bignum$+=STR$(c%-55) ELSE bignum$+=STR$(c%-48)
NEXT
REM MOD 97 on bignum$+"00" and subtract result from 98 to obtain control number
kk%=98-FNmod97(bignum$+"00")
REM Compare with control number in IBAN
match%=VALMID$(iban$,3,2)=kk%
REM Continue if control number matches
IF match% THEN
REM Append kk% to bignum$ and determine if MOD 97 results in 1
match%=FNmod97(bignum$+RIGHT$("0"+STR$kk%,2))=1
REM Continue if MOD 97
IF match% THEN
REM Was last test
ELSE
err$="result from modulo 97"
ENDIF
ELSE
err$="check digits, should be: "+STR$kk%
ENDIF
ELSE
err$="code length, expected length: "+STR$explen%
ENDIF
ELSE
err$="country code: "+LEFT$(iban$,2)
ENDIF
IF match% PRINT " "; ELSE PRINT "in";:err$="***error!*** invalid "+err$
PRINT "valid IBAN: ";iban$TAB(50)err$
ENDPROC
DEF FNmod97(num$)
LOCAL mod$
mod$=LEFT$(num$,2)
num$=MID$(num$,3)
WHILE num$>""
mod$=RIGHT$("0"+STR$(VAL(mod$+LEFT$(num$,7))MOD97),2)
num$=MID$(num$,8)
ENDWHILE
=VALmod$

View file

@ -0,0 +1,51 @@
( ( IBAN-check
= table country cd len N c
. (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)
: ?table
& @(!arg:?country [2 ?cd [4 ?arg)
& str$(!arg !country !cd):?arg
& ( !table:? (!country.?len) ?
& :?N
& ( @( !arg
: ?
( %@?c ?
& ( !c:#
| !c:~<A:~>Z
& asc$!c+-1*asc$A+10:?c
& 1+!len:?len
| !c:" "&:?c
|
)
& !N !c:?N
& ~
)
)
| str$!N:?N:#
& ( @(!N:? [!len)
& ( mod$(!N,97):1&out$OK
| out$"wrong check digits"
)
| out$"wrong length"
)
| @(!N:? ~#%?c ?)
& out$(str$("invalid character: '" !c "'"))
)
| out$(str$("invalid country code: '" !country "'"))
)
)
& IBAN-check$"GB82 WEST 1234 5698 7654 32 9"
& IBAN-check$"GX82 WEST 1234 5698 7654 32"
& IBAN-check$"GB82 WEST 1234 5698 7654 32"
& IBAN-check$GB82WEST12345698765432
& IBAN-check$"gb82 west 1234 5698 7654 32"
& IBAN-check$"GB82 TEST 1234 5698 7654 32"
& IBAN-check$"GB82 WEST 1243 5698 7654 32"
& IBAN-check$"GB82 west 1243 5698 7654 32"
);

72
Task/IBAN/C++/iban.cpp Normal file
View file

@ -0,0 +1,72 @@
#include <string>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <map>
#include <algorithm>
#include <cctype>
using namespace boost::algorithm ;
bool isValid ( const std::string &ibanstring ) {
static std::map<std::string, int> countrycodes
{ {"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 } } ;
std::string teststring( ibanstring ) ;
erase_all( teststring , " " ) ; //defined in boost/algorithm/string.hpp
if ( countrycodes.find( teststring.substr(0 , 2 )) == countrycodes.end( ) )
return false ;
if ( teststring.length( ) != countrycodes[ teststring.substr( 0 , 2 ) ] )
return false ;
if ( ! ( all ( teststring , is_alnum( ) ) ) )
return false ;
to_upper( teststring ) ;
teststring = teststring.append( teststring.substr( 0 , 4 ) ) ;
teststring.assign( teststring.substr( 4 ) ) ;
std::string numberstring ;//will contain the letter substitutions
for ( int i = 0 ; i < teststring.length( ) ; i++ ) {
if ( std::isdigit( teststring[ i ] ) )
numberstring = numberstring + teststring[ i ] ;
if ( std::isupper( teststring[ i ] ) )
numberstring = numberstring + std::to_string( static_cast<int>( teststring[ i ] ) - 55 ) ;
}
//implements a stepwise check for mod 97 in chunks of 9 at the first time
// , then in chunks of seven prepended by the last mod 97 operation converted
//to a string
int segstart = 0 ;
int step = 9 ;
std::string prepended ;
long number = 0 ;
while ( segstart < numberstring.length( ) - step ) {
number = std::stol( prepended + numberstring.substr( segstart , step ) ) ;
int remainder = number % 97 ;
prepended = std::to_string( remainder ) ;
if ( remainder < 10 )
prepended = "0" + prepended ;
segstart = segstart + step ;
step = 7 ;
}
number = std::stol( prepended + numberstring.substr( segstart )) ;
return ( number % 97 == 1 ) ;
}
int main( ) {
std::cout << "GB82 WEST 1234 5698 7654 32 is " << ( isValid( "GB82 WEST 1234 5698 7654 32" ) ? "" : "not " )
<< "valid!" << std::endl ;
std::cout << "GB82TEST12345698765432 is " << ( isValid( "GB82TEST12345698765432" ) ? "" : "not " )
<< "valid!" << std::endl ;
return 0 ;
}

120
Task/IBAN/C-sharp/iban-1.cs Normal file
View file

@ -0,0 +1,120 @@
public class IbanValidator : IValidateTypes
{
public ValidationResult Validate(string value)
{
// Check if value is missing
if (string.IsNullOrEmpty(value))
return ValidationResult.ValueMissing;
if (value.Length < 2)
return ValidationResult.ValueTooSmall;
var countryCode = value.Substring(0, 2).ToUpper();
int lengthForCountryCode;
var countryCodeKnown = _lengths.TryGetValue(countryCode, out lengthForCountryCode);
if (!countryCodeKnown)
{
return ValidationResult.CountryCodeNotKnown;
}
// Check length.
if (value.Length < lengthForCountryCode)
return ValidationResult.ValueTooSmall;
if (value.Length > lengthForCountryCode)
return ValidationResult.ValueTooBig;
value = value.ToUpper();
var newIban = value.Substring(4) + value.Substring(0, 4);
newIban = Regex.Replace(newIban, @"\D", match => ((int) match.Value[0] - 55).ToString());
var remainder = BigInteger.Parse(newIban) % 97;
if (remainder != 1)
return ValidationResult.ValueFailsModule97Check;
return ValidationResult.IsValid;
}
public enum ValidationResult
{
IsValid,
ValueMissing,
ValueTooSmall,
ValueTooBig,
ValueFailsModule97Check,
CountryCodeNotKnown
}
private static Dictionary<string, int> _lengths = new Dictionary<string, int>
{
{"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}
};
}

100
Task/IBAN/C-sharp/iban-2.cs Normal file
View file

@ -0,0 +1,100 @@
public class When_the_IbanValidator_is_told_to_Validate
{
[Fact]
public void It_should_return_an_error_when_there_is_no_value_provided()
{
// Assert
const string value = "";
var validator = new IbanValidator();
// Act
var result = validator.Validate(value);
// Assert
Assert.Equal(ValidationResult.ValueMissing, result);
}
[Fact]
public void It_should_return_an_error_when_the_value_length_is_to_short()
{
// Assert
const string value = "BE1800165492356";
var validator = new IbanValidator();
// Act
var result = validator.Validate(value);
// Assert
Assert.Equal(ValidationResult.ValueTooSmall, result);
}
[Fact]
public void It_should_return_an_error_when_the_value_length_is_to_big()
{
// Assert
const string value = "BE180016549235656";
var validator = new IbanValidator();
// Act
var result = validator.Validate(value);
// Assert
Assert.Equal(ValidationResult.ValueTooBig, result);
}
[Fact]
public void It_should_return_an_error_when_the_value_fails_the_module_check()
{
// Assert
const string value = "BE18001654923566";
var validator = new IbanValidator();
// Act
var result = validator.Validate(value);
// Assert
Assert.Equal(ValidationResult.ValueFailsModule97Check, result);
}
[Fact]
public void It_should_return_an_error_when_an_unkown_country_prefix_used()
{
// Assert
const string value = "XX82WEST12345698765432";
var validator = new IbanValidator();
// Act
var result = validator.Validate(value);
// Assert
Assert.Equal(ValidationResult.CountryCodeNotKnown, result);
}
[Fact]
public void It_should_return_valid_when_a_valid_value_is_provided()
{
// Assert
const string value = "BE18001654923565";
var validator = new IbanValidator();
// Act
var result = validator.Validate(value);
// Assert
Assert.Equal(ValidationResult.IsValid, result);
}
[Fact]
public void It_should_return_valid_when_a_valid_foreign_value_is_provided()
{
// Assert
const string value = "GB82WEST12345698765432";
var validator = new IbanValidator();
// Act
var result = validator.Validate(value);
// Assert
Assert.Equal(ValidationResult.IsValid, result);
}
}

97
Task/IBAN/C/iban.c Normal file
View file

@ -0,0 +1,97 @@
#include <alloca.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define V(cc, exp) if (!strncmp(iban, cc, 2)) return len == exp
/* Validate country code against expected length. */
int valid_cc(const char *iban, int len)
{
V("AL", 28); V("AD", 24); V("AT", 20); V("AZ", 28); V("BE", 16); V("BH", 22); V("BA", 20); V("BR", 29);
V("BG", 22); V("CR", 21); V("HR", 21); V("CY", 28); V("CZ", 24); V("DK", 18); V("DO", 28); V("EE", 20);
V("FO", 18); V("FI", 18); V("FR", 27); V("GE", 22); V("DE", 22); V("GI", 23); V("GR", 27); V("GL", 18);
V("GT", 28); V("HU", 28); V("IS", 26); V("IE", 22); V("IL", 23); V("IT", 27); V("KZ", 20); V("KW", 30);
V("LV", 21); V("LB", 28); V("LI", 21); V("LT", 20); V("LU", 20); V("MK", 19); V("MT", 31); V("MR", 27);
V("MU", 30); V("MC", 27); V("MD", 24); V("ME", 22); V("NL", 18); V("NO", 15); V("PK", 24); V("PS", 29);
V("PL", 28); V("PT", 25); V("RO", 24); V("SM", 27); V("SA", 24); V("RS", 22); V("SK", 24); V("SI", 19);
V("ES", 24); V("SE", 24); V("CH", 21); V("TN", 24); V("TR", 26); V("AE", 23); V("GB", 22); V("VG", 24);
return 0;
}
/* Remove blanks from s in-place, return its new length. */
int strip(char *s)
{
int i = -1, m = 0;
while(s[++i]) {
s[i - m] = s[i];
m += s[i] <= 32;
}
s[i - m] = 0;
return i - m;
}
/* Calculate the mod 97 of an arbitrarily large number (as a string). */
int mod97(const char *s, int len)
{
int i, j, parts = len / 7;
char rem[10] = "00";
for (i = 1; i <= parts + (len % 7 != 0); ++i) {
strncpy(rem + 2, s + (i - 1) * 7, 7);
j = atoi(rem) % 97;
rem[0] = j / 10 + '0';
rem[1] = j % 10 + '0';
}
return atoi(rem) % 97;
}
int valid_iban(char *iban)
{
int i, j, l = 0, sz = strip(iban);
char *rot, *trans;
/* Ensure upper alphanumeric input and count letters. */
for (i = 0; i < sz; ++i) {
if (!isdigit(iban[i]) && !isupper(iban[i]))
return 0;
l += !!isupper(iban[i]);
}
if (!valid_cc(iban, sz))
return 0;
/* Move the first four characters to the end. */
rot = alloca(sz);
strcpy(rot, iban + 4);
strncpy(rot + sz - 4, iban, 4);
/* Allocate space for the transformed IBAN. */
trans = alloca(sz + l);
trans[sz + l] = 0;
/* Convert A to 10, B to 11, etc. */
for (i = j = 0; i < sz; ++i, ++j) {
if (isdigit(rot[i]))
trans[j] = rot[i];
else {
trans[j] = (rot[i] - 55) / 10 + '0';
trans[++j] = (rot[i] - 55) % 10 + '0';
}
}
return mod97(trans, sz + l) == 1;
}
int main(int _, char **argv)
{
while (--_, *++argv)
printf("%s is %svalid.\n", *argv, valid_iban(*argv) ? "" : "in");
return 0;
}

161
Task/IBAN/COBOL/iban.cobol Normal file
View file

@ -0,0 +1,161 @@
IDENTIFICATION DIVISION.
PROGRAM-ID. iban-main.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 iban PIC X(50).
01 iban-flag PIC X.
88 is-valid VALUE "Y", FALSE "N".
PROCEDURE DIVISION.
main-line.
MOVE "GB82 WEST 1234 5698 7654 32" TO iban
PERFORM display-validity
MOVE "GB82 TEST 1234 5698 7654 32" TO iban
PERFORM display-validity
GOBACK
.
display-validity.
CALL "validate-iban" USING CONTENT iban, REFERENCE iban-flag
IF is-valid
DISPLAY FUNCTION TRIM(iban) " is valid."
ELSE
DISPLAY FUNCTION TRIM(iban) " is not valid."
END-IF
.
END PROGRAM iban-main.
IDENTIFICATION DIVISION.
PROGRAM-ID. validate-iban.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 country-lengths-area VALUE "AD24AE23AL28AT20AZ28BA20BE16"
& "BG22BH22BR29CH21CR21CY28CZ24DE22DK18DO28EE20ES24FI18FO18F"
& "R27GB22GE22GI23GL18GR27GT28HR21HU28IE22IL23IS26IT27KW30KZ"
& "20LB28LI21LT20LU20LV21MC27MD24ME22MK19MR27MT31MU30NL18NO1"
& "5PK24PL28PS29PT25RO24RS22SA24SE24SI19SK24SM27TN24TR26VG24"
.
03 country-lengths OCCURS 64 TIMES
INDEXED BY country-lengths-idx.
05 country-code PIC XX.
05 country-len PIC 99.
01 offset PIC 99.
01 i PIC 99.
01 len PIC 99.
LINKAGE SECTION.
01 iban PIC X(50).
01 valid-flag PIC X.
88 is-valid VALUE "Y", FALSE "N".
PROCEDURE DIVISION USING iban, valid-flag.
MOVE FUNCTION UPPER-CASE(iban) TO iban
CALL "remove-spaces" USING iban
*> Check if country-code and length are correct
INITIALIZE len
INSPECT iban TALLYING len FOR CHARACTERS BEFORE SPACE
SET country-lengths-idx TO 1
SEARCH country-lengths
AT END
SET is-valid TO FALSE
GOBACK
WHEN country-code (country-lengths-idx) = iban (1:2)
IF country-len (country-lengths-idx) NOT = len
SET is-valid TO FALSE
GOBACK
END-IF
END-SEARCH
CALL "create-iban-number" USING CONTENT len, REFERENCE iban
*> Mod 97 number formed.
IF FUNCTION MOD(iban, 97) = 1
SET is-valid TO TRUE
ELSE
SET is-valid TO FALSE
END-IF
.
IDENTIFICATION DIVISION.
PROGRAM-ID. remove-spaces.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 i PIC 99.
01 offset PIC 99.
LINKAGE SECTION.
01 str PIC X(50).
PROCEDURE DIVISION USING str.
INITIALIZE offset
PERFORM VARYING i FROM 1 BY 1 UNTIL i > 50
EVALUATE TRUE
WHEN str (i:1) = SPACE
ADD 1 TO offset
WHEN offset NOT = ZERO
MOVE str (i:1) TO str (i - offset:1)
END-EVALUATE
END-PERFORM
MOVE SPACES TO str (50 - offset + 1:)
.
END PROGRAM remove-spaces.
IDENTIFICATION DIVISION.
PROGRAM-ID. create-iban-number.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 first-four PIC X(4).
01 iban-num PIC X(50).
01 digit-num PIC 99 VALUE 1.
01 i PIC 99.
01 letter-num PIC 99.
LINKAGE SECTION.
01 len PIC 99.
01 iban PIC X(50).
PROCEDURE DIVISION USING len, iban.
*> Move characters into final positions.
MOVE iban (1:4) TO first-four
MOVE iban (5:) TO iban
MOVE first-four TO iban (len - 3:)
*> Convert letters to numbers.
INITIALIZE iban-num, digit-num ALL TO VALUE
PERFORM VARYING i FROM 1 BY 1
UNTIL i > len OR iban (i:1) = SPACE
IF iban (i:1) IS NUMERIC
MOVE iban (i:1) TO iban-num (digit-num:1)
ADD 1 TO digit-num
ELSE
COMPUTE letter-num =
FUNCTION ORD(iban (i:1)) - FUNCTION ORD("A") + 10
MOVE letter-num TO iban-num (digit-num:2)
ADD 2 TO digit-num
END-IF
END-PERFORM
MOVE iban-num TO iban
.
END PROGRAM create-iban-number.
END PROGRAM validate-iban.

View file

@ -0,0 +1,98 @@
Class Utils.Validate [ Abstract ]
{
ClassMethod VerifyIBAN(pIBAN As %String = "") As %Boolean
{
// remove spaces and define parts
Set iban=$Translate(pIBAN, " ")
Set cc=$Extract(iban, 1, 2)
Set cd=$Extract(iban, 3, 4)
Set bban=$Extract(iban, 5, *)
// ensure IBAN is correct format
If $Match(iban, ..GetIBANPattern(cc))=0 Quit 0
// compare result and return
Quit cd=..GetIBANCheckDigit(cc, bban)
}
ClassMethod GetIBANCheckDigit(pCC As %String, pBBAN As %String) As %Integer [ Internal, Private ]
{
Set str=pBBAN_pCC_"00"
For i=1:1 {
Set chr=$Extract(str, i) If chr="" Quit
If chr?1U Set $Extract(str, i)=$ASCII(chr)-55
}
Set cd=98-..GetModulus(str, 97)
Quit $Select($Length(cd)=2: cd, 1: "0"_cd)
}
ClassMethod GetModulus(pNum As %Integer, pDiv As %Integer) As %Integer [ Internal, Private ]
{
While $Length(pNum)>9 {
Set $Extract(pNum, 1, 9)=$Extract(pNum, 1, 9)#pDiv
}
Quit pNum#pDiv
}
ClassMethod GetIBANPattern(pCC As %String = "") As %String [ Internal, Private ]
{
Quit $Case(pCC,
"AL": "^AL\d{10}[0-9A-Z]{16}$",
"AD": "^AD\d{10}[0-9A-Z]{12}$",
"AT": "^AT\d{18}$",
"BH": "^BH\d{2}[A-Z]{4}[0-9A-Z]{14}$",
"BE": "^BE\d{14}$",
"BA": "^BA\d{18}$",
"BG": "^BG\d{2}[A-Z]{4}\d{6}[0-9A-Z]{8}$",
"HR": "^HR\d{19}$",
"CY": "^CY\d{10}[0-9A-Z]{16}$",
"CZ": "^CZ\d{22}$",
"DK": "^DK\d{16}$|^FO\d{16}$|^GL\d{16}$",
"DO": "^DO\d{2}[0-9A-Z]{4}\d{20}$",
"EE": "^EE\d{18}$",
"FI": "^FI\d{16}$",
"FR": "^FR\d{12}[0-9A-Z]{11}\d{2}$",
"GE": "^GE\d{2}[A-Z]{2}\d{16}$",
"DE": "^DE\d{20}$",
"GI": "^GI\d{2}[A-Z]{4}[0-9A-Z]{15}$",
"GR": "^GR\d{9}[0-9A-Z]{16}$",
"HU": "^HU\d{26}$",
"IS": "^IS\d{24}$",
"IE": "^IE\d{2}[A-Z]{4}\d{14}$",
"IL": "^IL\d{21}$",
"IT": "^IT\d{2}[A-Z]\d{10}[0-9A-Z]{12}$",
"KZ": "^[A-Z]{2}\d{5}[0-9A-Z]{13}$",
"KW": "^KW\d{2}[A-Z]{4}22!$",
"LV": "^LV\d{2}[A-Z]{4}[0-9A-Z]{13}$",
"LB": "^LB\d{6}[0-9A-Z]{20}$",
"LI": "^LI\d{7}[0-9A-Z]{12}$",
"LT": "^LT\d{18}$",
"LU": "^LU\d{5}[0-9A-Z]{13}$",
"MK": "^MK\d{5}[0-9A-Z]{10}\d{2}$",
"MT": "^MT\d{2}[A-Z]{4}\d{5}[0-9A-Z]{18}$",
"MR": "^MR13\d{23}$",
"MU": "^MU\d{2}[A-Z]{4}\d{19}[A-Z]{3}$",
"MC": "^MC\d{12}[0-9A-Z]{11}\d{2}$",
"ME": "^ME\d{20}$",
"NL": "^NL\d{2}[A-Z]{4}\d{10}$",
"NO": "^NO\d{13}$",
"PL": "^PL\d{10}[0-9A-Z]{,16}n$",
"PT": "^PT\d{23}$",
"RO": "^RO\d{2}[A-Z]{4}[0-9A-Z]{16}$",
"SM": "^SM\d{2}[A-Z]\d{10}[0-9A-Z]{12}$",
"SA": "^SA\d{4}[0-9A-Z]{18}$",
"RS": "^RS\d{20}$",
"SK": "^SK\d{22}$",
"SI": "^SI\d{17}$",
"ES": "^ES\d{22}$",
"SE": "^SE\d{22}$",
"CH": "^CH\d{7}[0-9A-Z]{12}$",
"TN": "^TN59\d{20}$",
"TR": "^TR\d{7}[0-9A-Z]{17}$",
"AE": "^AE\d{21}$",
"GB": "^GB\d{2}[A-Z]{4}\d{14}$",
: " ")
}
}

View file

@ -0,0 +1,24 @@
(def explen
{"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})
(defn valid-iban? [iban]
(let [iban (apply str (remove #{\space \tab} iban))]
(cond
; Ensure upper alphanumeric input.
(not (re-find #"^[\dA-Z]+$" iban)) false
; Validate country code against expected length.
(not= (explen (subs iban 0 2)) (count iban)) false
:else
(let [rot (flatten (apply conj (split-at 4 iban)))
trans (map #(read-string (str "36r" %)) rot)]
(= 1 (mod (bigint (apply str trans)) 97))))))
(prn (valid-iban? "GB82 WEST 1234 5698 7654 32") ; true
(valid-iban? "GB82 TEST 1234 5698 7654 32")) ; false

View file

@ -0,0 +1,60 @@
;;
;; List of the IBAN code lengths per country.
;;
(defvar *IBAN-code-length* '((15 . ("NO"))
(16 . ("BE"))
(18 . ("DK" "FO" "FI" "GL" "NL"))
(19 . ("MK" "SI"))
(20 . ("AT" "BA" "EE" "KZ" "LT" "LU"))
(21 . ("CR" "HR" "LV" "LI" "CH"))
(22 . ("BH" "BG" "GE" "DE" "IE" "ME" "RS" "GB"))
(23 . ("GI" "IL" "AE"))
(24 . ("AD" "CZ" "MD" "PK" "RO" "SA" "SK" "ES" "SE" "TN" "VG"))
(25 . ("PT"))
(26 . ("IS" "TR"))
(27 . ("FR" "GR" "IT" "MR" "MC" "SM"))
(28 . ("AL" "AZ" "CY" "DO" "GT" "HU" "LB" "PL"))
(29 . ("BR" "PS"))
(30 . ("KW" "MU"))
(31 . ("MT"))))
;;
;; The IBAN-character function verifies whether the number contains the correct characters only. There is
;; a built in function to verify for alphanumeric characters, but it includes characters beyond ASCII range.
;;
(defun IBAN-characters (iban)
(flet ((valid-alphanum (ch) (or (and (char<= #\A ch) (char>= #\Z ch)) (and (char<= #\0 ch) (char>= #\9 ch)))))
(loop :for char :across iban
:finally (return t)
:do
(when (not (valid-alphanum char))
(return nil)))))
;;
;; The function IBAN-length verifies that the length of the number is correct. The code lengths
;; are retrieved from the table *IBAN-code-lengths*.
;;
(defun IBAN-length (iban)
(loop :for (len . country) :in *IBAN-code-length*
:with iban-country = (subseq iban 0 2)
:do
(when (find iban-country country :test #'string=) (return (= len (length iban))))))
;;
;; The function IBAN-to-integer converts an IBAN code into an integer number.
;; Note: The conversion follows the rules stated in the wiki page.
;;
(defun IBAN-to-integer (iban)
(let ((character-base (- (char-code #\A) 10)))
(parse-integer
(format nil "~{~a~}" (map 'list #'(lambda(X) (if (alpha-char-p X) (- (char-code X) character-base) X ))
(concatenate 'string (subseq iban 4) (subseq iban 0 4)))))))
;;
;; The function IBAN-verify checks that the code contains right character set, has the
;; country specific length and has the correct check sum.
;;
(defun IBAN-verify (iban)
(flet ((validp (X) (and (IBAN-characters X)
(IBAN-length X)
(= 1 (mod (IBAN-to-integer X) 97)))))
(validp (remove #\Space iban))))

37
Task/IBAN/D/iban.d Normal file
View file

@ -0,0 +1,37 @@
import std.stdio, std.string, std.regex, std.conv, std.bigint,
std.algorithm, std.ascii;
immutable int[string] country2len;
static this() {
country2len = ["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];
}
bool validIBAN(string iban) {
// Ensure upper alphanumeric input.
iban = iban.removechars(whitespace);
if (!iban.match(r"^[\dA-Z]+$"))
return false;
// Validate country code against expected length.
if (iban.length != country2len[iban[0 .. 2]])
return false;
// Shift and convert. BASE 36: 0..9,A..Z -> 0..35.
iban = iban[4 .. $] ~ iban[0 .. 4];
return iban.map!(c => [c].to!int(36).text).join.BigInt % 97 == 1;
}
void main() {
foreach (account; ["GB82 WEST 1234 5698 7654 32",
"GB82 TEST 1234 5698 7654 32"])
writefln("%s validation is: %s", account, account.validIBAN);
}

61
Task/IBAN/Go/iban.go Normal file
View file

@ -0,0 +1,61 @@
package main
import (
"fmt"
"strings"
"strconv"
"math/big"
)
var lCode = map[string]int {
"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,
}
var sCode = map[string]int {
"1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
"A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15, "G": 16,
"H": 17, "I": 18, "J": 19, "K": 20, "L": 21, "M": 22, "N": 23,
"O": 24, "P": 25, "Q": 26, "R": 27, "S": 28, "T": 29, "U": 30,
"V": 31, "W": 32, "X": 33, "Y": 34, "Z": 35,
}
func main() {
var iban string
var r, s, t, st []string
u := new(big.Int)
v := new(big.Int)
w := new(big.Int)
iban = "GB82 TEST 1234 5698 7654 32"
r = strings.Split(iban, " ")
s = strings.Split(r[0], "")
t = strings.Split(r[1], "")
st = []string{ strconv.Itoa(sCode[t[0]]),
strconv.Itoa(sCode[t[1]]),
strconv.Itoa(sCode[t[2]]),
strconv.Itoa(sCode[t[3]]),
strings.Join(r[2:6], ""),
strconv.Itoa(sCode[s[0]]),
strconv.Itoa(sCode[s[1]]),
strings.Join(s[2:4], ""),
}
u.SetString(strings.Join(st, ""), 10)
v.SetInt64(97)
w.Mod(u, v)
if w.Uint64() == 1 && lCode[strings.Join(s[0:2], "")] == len(strings.Join(r, "")) {
fmt.Printf("IBAN %s looks good!\n", iban)
} else {
fmt.Printf("IBAN %s looks wrong!\n", iban)
}
}

View file

@ -0,0 +1,16 @@
def validateIBAN(String iban) {
def iso = [AL: 28, AD: 24, AT: 20, AZ: 28, BE: 16, BH: 22, BA: 20, BR: 29, BG: 22,
HR: 21, CY: 28, CZ: 24, DK: 18, DO: 28, EE: 20, FO: 18, FI: 18, FR: 27, GE: 22, DE: 22, GI: 23,
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, GR: 27, CR: 21]
iban = iban.replaceAll(/\s/, '').toUpperCase()
if (iban.size() < 4 || iso[iban[0..1]] != iban.size()) return false
iban = iban[4..-1] + iban[0..<4]
def number = iban.collect { Character.digit(it as char, 36) }.join('')
(number as BigInteger).mod(97) == 1
}

View file

@ -0,0 +1,7 @@
[ 'GB82 WEST 1234 5698 7654 32',
'GB82 TEST 1234 5698 7654 32',
'GB81 WEST 1234 5698 7654 32',
'SA03 8000 0000 6080 1016 7519',
'CH93 0076 2011 6238 5295 7' ].each { iban ->
println "$iban is ${validateIBAN(iban) ? 'valid' : 'invalid'}"
}

55
Task/IBAN/Haskell/iban.hs Normal file
View file

@ -0,0 +1,55 @@
import Data.Char (toUpper)
validateIBAN :: String -> Either String String
validateIBAN [] = Left "No IBAN number."
validateIBAN xs =
case lookupCountry of
Nothing -> invalidBecause "Country does not exist."
Just l -> if length normalized /= l
then invalidBecause "Number length does not match."
else check
where
-- remove blanks and make all letters uppercase
normalized = map toUpper $ concat $ words xs
-- get the country code
country = take 2 normalized
-- search number length
lookupCountry = lookup country countries
countries :: [(String, Int)]
countries = zip (words "AL AT BE BA BG HR CZ DO FO FR DE GR GT \
\IS IL KZ LV LI LU MT MU MD NL PK PL RO SA SK ES CH TR GB \
\AD AZ BH BR CR CY DK EE FI GE GI GL HU IE IT KW LB LT MK \
\MR MC ME NO PS PT SM RS SI SE TN AE VG")
[28,20,16,20,22,21,24,28,18,27,22,27,28,26,23,20,21,21,20,
31,30,24,18,24,28,24,24,24,24,21,26,22,24,28,22,29,21,28,18,
20,18,22,23,18,28,22,27,30,28,20,19,27,27,22,15,29,25,27,22,
19,24,24,23,24]
digits = ['0'..'9']
letters = ['A'..'Z']
-- letters to be replaced
replDigits = zip letters $ map show [10..35]
-- digits and letters allowed in the IBAN number
validDigits = digits ++ letters
-- see if all digits and letters in the IBAN number are allowed
sane = all (`elem` validDigits) normalized
-- take the first 4 digits from the number and put them at its end
(p1, p2) = splitAt 4 normalized
p3 = p2 ++ p1
-- convert the letters to numbers and
-- convert the result to an integer
p4 :: Integer
p4 = read $ concat $ convertLetters p3
convertLetters [] = []
convertLetters (x:xs)
| x `elem` digits = [x] : convertLetters xs
| otherwise = let (Just ys) = lookup x replDigits
in ys : convertLetters xs
-- see if the number is valid
check = if sane
then if p4 `mod` 97 == 1
then Right xs
else invalidBecause "Validation failed."
else invalidBecause "Number contains illegal digits."
invalidBecause reason = Left $ "Invalid IBAN number " ++ xs ++
": " ++ reason

34
Task/IBAN/J/iban.j Normal file
View file

@ -0,0 +1,34 @@
NB. delete any blank characters
delblk =. #~ ' '&~:
NB. rearrange
rot =. '00' ,~ 2&}. @: (2&|.)
NB. characters -> "digits"
dig =. a. {~ (a.i.'0')+i.10
dig =. dig,a. {~ (a.i.'A')+i.26
todig =. dig&i.
coded =. [: ". 'x' ,~ delblk @: ": @: todig
NB. calculate check sum
cs =: 98 - 97 | coded @: rot @: delblk f.
NB. check sum as text
cstxt =. _2{. '0', [: ": cs
NB. replace first two characters
chgps =. [,2}.]
NB. shift country code
rotlc =. 2&|.
NB. insert check digits (position 3 and 4)
insertps =. chgps &.rotlc
NB. IBAN with newly calculated check digits
ibancd =: (cstxt insertps ]) f.
NB. check / generate check digits
ibancheck =: ] (]`('ok'"_) @. -:) ibancd
NB. groups of four characters
insertblk =. #~ # $ 1 1 1 1j1"_
quads =: insertblk @: delblk f.
NB. IBAN
iban =: quads @: ibancheck

47
Task/IBAN/Java/iban.java Normal file
View file

@ -0,0 +1,47 @@
import java.math.BigInteger;
import java.util.*;
public class IBAN {
static final Map<String, Integer> isoPairs;
static final String iso = "AL28 AD24 AT20 AZ28 BE16 BH22 BA20 BR29 BG22 "
+ "HR21 CY28 CZ24 DK18 DO28 EE20 FO18 FI18 FR27 GE22 DE22 GI23 "
+ "GL18 GT28 HU28 IS26 IE22 IL23 IT27 KZ20 KW30 LV21 LB28 LI21 "
+ "LT20 LU20 MK19 MT31 MR27 MU30 MC27 MD24 ME22 NL18 NO15 PK24 "
+ "PS29 PL28 PT25 RO24 SM27 SA24 RS22 SK24 SI19 ES24 SE24 CH21 "
+ "TN24 TR26 AE23 GB22 VG24 GR27 CR21";
static {
isoPairs = new HashMap<>();
for (String p : iso.split(" "))
isoPairs.put(p.substring(0, 2), Integer.parseInt(p.substring(2)));
}
public static void main(String[] args) {
for (String iban : new String[]{"GB82 WEST 1234 5698 7654 32",
"GB82 TEST 1234 5698 7654 32",
"GB81 WEST 1234 5698 7654 32",
"SA03 8000 0000 6080 1016 7519",
"CH93 0076 2011 6238 5295 7"})
System.out.printf("%s is valid: %s%n%n", iban, validateIBAN(iban));
}
static boolean validateIBAN(String iban) {
iban = iban.replaceAll("\\s", "").toUpperCase();
int len = iban.length();
if (len < 4 || isoPairs.get(iban.substring(0, 2)) != len)
return false;
iban = iban.substring(4) + iban.substring(0, 4);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++)
sb.append(Character.digit(iban.charAt(i), 36));
BigInteger bigInt = new BigInteger(sb.toString());
return bigInt.mod(new BigInteger("97")).intValue() == 1;
}
}

30
Task/IBAN/MATLAB/iban-1.m Normal file
View file

@ -0,0 +1,30 @@
function valid = validateIBAN(iban)
% Determine if International Bank Account Number is valid IAW ISO 13616
% iban - string containing account number
if length(iban) < 5
valid = false;
else
iban(iban == ' ') = ''; % Remove spaces
iban = lower([iban(5:end) iban(1:4)])+0; % Rearrange and convert
iban(iban > 96 & iban < 123) = iban(iban > 96 & iban < 123)-87; % Letters
iban(iban > 47 & iban < 58) = iban(iban > 47 & iban < 58)-48; % Numbers
valid = piecewiseMod97(iban) == 1;
end
end
function result = piecewiseMod97(x)
% Conduct a piecewise version of mod(x, 97) to support large integers
% x is a vector of integers
x = sprintf('%d', x); % Get to single-digits per index
nDig = length(x);
i1 = 1;
i2 = min(9, nDig);
prefix = '';
while i1 <= nDig
y = str2double([prefix x(i1:i2)]);
result = mod(y, 97);
prefix = sprintf('%d', result);
i1 = i2+1;
i2 = min(i1+8, nDig);
end
end

11
Task/IBAN/MATLAB/iban-2.m Normal file
View file

@ -0,0 +1,11 @@
tests = {'GB82 WEST 1234 5698 7654 32' ;
'GB82 TEST 1234 5698 7654 32' ;
'CH93 0076 2011 6238 5295 7' ;
'SA03 8000 0000 6080 1016 7519' ;
'SA03 1234 5678 9101 1121 3141' ;
'GB29 NWBK 6016 1331 9268 19' ;
'GB29' ;
'GR16 0110 1250 0000 0001 2300 695'};
for k = 1:length(tests)
fprintf('%s -> %svalid\n', tests{k}, char(~validateIBAN(tests{k}).*'in'))
end

View file

@ -0,0 +1,29 @@
CountryCodes={{"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}};
ClearAll[IBANVerify]
IBANVerify[input_String]:=Module[{i,cc,rules},
i=StringReplace[StringTrim[input],{" "->"","\t"->""}];
cc=StringTake[i,2];
If[MemberQ[CountryCodes[[All,1]],cc]
,
cc=Select[CountryCodes,First[#]==cc&][[1,2]];
If[cc==StringLength[i]
,
i=StringRotateLeft[i,4];
i=Characters[ToUpperCase[i]];
rules=Rule@@@({CharacterRange["A","Z"],Range[10,35]}\[Transpose]);
i=i/.rules;
i=ToExpression/@i;
i=FromDigits[Flatten[IntegerDigits/@i]];
If[Mod[i,97]===1
,
True
,
False
]
,
False
]
,
False
]
]

View file

@ -0,0 +1,4 @@
IBANVerify["GB82 WEST 1234 5698 7654 32"]
IBANVerify["GB82 WEST 1234 5698 7654 323"]
IBANVerify["GB82 WEST 1234 5698 7654 31"]
IBANVerify["XX82 WEST 1234 5698 7654 323"]

View file

@ -0,0 +1,161 @@
MODULE IBAN;
IMPORT
Out,
Err,
ADT:Dictionary,
Object:Boxed,
Object:BigInt,
Object,
Strings,
IntStr;
TYPE
IBANLen = Boxed.LongInt;
VAR
nations: Dictionary.Dictionary(STRING,IBANLen);
PROCEDURE Check*(iban: ARRAY OF CHAR): BOOLEAN;
VAR
country,ibanStr: Object.String;
nLetter: ARRAY 3 OF CHAR;
block: ARRAY 5 OF CHAR;
numIban: ARRAY 256 OF CHAR;
num,den,res: BigInt.BigInt;
ibanLen: IBANLen;
i: LONGINT;
BEGIN
ibanStr := Object.NewLatin1(iban);
country := ibanStr.Substring(0,2);
IF ~nations.HasKey(country) THEN
Err.Object("Country " + country + " has not IBAN codes. ");
RETURN FALSE;
END;
ibanLen := nations.Get(country);
IF SHORT(ibanLen.value) # Strings.Length(iban) THEN
Err.Object("IBAN length incorrect for " + country +". ");
RETURN FALSE
END;
block[0] := 0X;
Strings.Extract(iban,0,4,block);
Strings.Delete(iban,0,4);Strings.Append(block,iban);
numIban[0] := 0X;
FOR i := 0 TO LEN(iban) - 1 DO
nLetter[0] := 0X;
IF (iban[i] >= 'A') & (iban[i] <= 'Z') THEN
IntStr.IntToStr(ORD(iban[i]) - ORD('A') + 10,nLetter);
ELSE
nLetter[0] := iban[i];
nLetter[1] := 0X
END;
Strings.Append(nLetter,numIban);
END;
Strings.Append(0X,numIban);
num := BigInt.New(Object.NewLatin1(numIban),10);
den := BigInt.New("97",10);
res := num.Mod(den);
IF res.Equals(BigInt.one) THEN
RETURN TRUE
ELSE
Err.String("IBAN code check failed. ");
RETURN FALSE
END
END Check;
PROCEDURE CodeLengthFor*(country: ARRAY OF CHAR): LONGINT;
VAR
countryStr: Object.String;
ibanLen: IBANLen;
BEGIN
countryStr := Object.NewLatin1(country);
ibanLen := Boxed.zeroLongInt;
IF nations.HasKey(countryStr) THEN
ibanLen := nations.Get(countryStr)
END;
RETURN ibanLen.value
END CodeLengthFor;
PROCEDURE Test*;
PROCEDURE DoCheck(iban: ARRAY OF CHAR);
BEGIN
Out.String("IBAN[");Out.String(iban);Out.String("]=");Out.Bool(Check(iban));
Out.Ln
END DoCheck;
BEGIN
DoCheck("CH9300762011623852957");
DoCheck("GB82WEST12345698765432");
DoCheck("SA0380000000608010167519");
DoCheck("XX0380000000608010167519");
END Test;
BEGIN
nations := NEW(Dictionary.Dictionary(STRING,Boxed.LongInt));
nations.Set("AL",NEW(IBANLen,28));
nations.Set("AD",NEW(IBANLen,24));
nations.Set("AT",NEW(IBANLen,20));
nations.Set("AZ",NEW(IBANLen,28));
nations.Set("BE",NEW(IBANLen,16));
nations.Set("BH",NEW(IBANLen,22));
nations.Set("BA",NEW(IBANLen,20));
nations.Set("BR",NEW(IBANLen,29));
nations.Set("BG",NEW(IBANLen,22));
nations.Set("CR",NEW(IBANLen,21));
nations.Set("HR",NEW(IBANLen,21));
nations.Set("CY",NEW(IBANLen,28));
nations.Set("CZ",NEW(IBANLen,24));
nations.Set("DK",NEW(IBANLen,18));
nations.Set("DO",NEW(IBANLen,28));
nations.Set("EE",NEW(IBANLen,20));
nations.Set("FO",NEW(IBANLen,18));
nations.Set("FI",NEW(IBANLen,18));
nations.Set("FR",NEW(IBANLen,27));
nations.Set("GE",NEW(IBANLen,22));
nations.Set("DE",NEW(IBANLen,22));
nations.Set("GI",NEW(IBANLen,23));
nations.Set("GR",NEW(IBANLen,27));
nations.Set("GL",NEW(IBANLen,18));
nations.Set("GT",NEW(IBANLen,28));
nations.Set("HU",NEW(IBANLen,28));
nations.Set("IS",NEW(IBANLen,26));
nations.Set("IE",NEW(IBANLen,22));
nations.Set("IL",NEW(IBANLen,23));
nations.Set("IT",NEW(IBANLen,27));
nations.Set("KZ",NEW(IBANLen,20));
nations.Set("KW",NEW(IBANLen,30));
nations.Set("LV",NEW(IBANLen,21));
nations.Set("LB",NEW(IBANLen,28));
nations.Set("LI",NEW(IBANLen,21));
nations.Set("LT",NEW(IBANLen,20));
nations.Set("LU",NEW(IBANLen,20));
nations.Set("MK",NEW(IBANLen,19));
nations.Set("MT",NEW(IBANLen,31));
nations.Set("MR",NEW(IBANLen,27));
nations.Set("MU",NEW(IBANLen,30));
nations.Set("MC",NEW(IBANLen,27));
nations.Set("MD",NEW(IBANLen,24));
nations.Set("ME",NEW(IBANLen,22));
nations.Set("NL",NEW(IBANLen,18));
nations.Set("NO",NEW(IBANLen,15));
nations.Set("PK",NEW(IBANLen,24));
nations.Set("PS",NEW(IBANLen,29));
nations.Set("PL",NEW(IBANLen,28));
nations.Set("PT",NEW(IBANLen,25));
nations.Set("RO",NEW(IBANLen,24));
nations.Set("SM",NEW(IBANLen,27));
nations.Set("SA",NEW(IBANLen,24));
nations.Set("RS",NEW(IBANLen,22));
nations.Set("SK",NEW(IBANLen,24));
nations.Set("SI",NEW(IBANLen,19));
nations.Set("ES",NEW(IBANLen,24));
nations.Set("SE",NEW(IBANLen,24));
nations.Set("CH",NEW(IBANLen,21));
nations.Set("TN",NEW(IBANLen,24));
nations.Set("TR",NEW(IBANLen,26));
nations.Set("AE",NEW(IBANLen,23));
nations.Set("GB",NEW(IBANLen,22));
nations.Set("VG",NEW(IBANLen,24));
Test;
END IBAN.

19
Task/IBAN/Perl-6/iban.pl6 Normal file
View file

@ -0,0 +1,19 @@
subset IBAN of Str where sub ($_ is copy) {
s:g/\s//;
return False if m/<-[ 0..9 A..Z a..z ]>/ or .chars != <
AD 24 AE 23 AL 28 AT 20 AZ 28 BA 20 BE 16 BG 22 BH 22 BR 29 CH 21
CR 21 CY 28 CZ 24 DE 22 DK 18 DO 28 EE 20 ES 24 FI 18 FO 18 FR 27
GB 22 GE 22 GI 23 GL 18 GR 27 GT 28 HR 21 HU 28 IE 22 IL 23 IS 26
IT 27 KW 30 KZ 20 LB 28 LI 21 LT 20 LU 20 LV 21 MC 27 MD 24 ME 22
MK 19 MR 27 MT 31 MU 30 NL 18 NO 15 PK 24 PL 28 PS 29 PT 25 RO 24
RS 22 SA 24 SE 24 SI 19 SK 24 SM 27 TN 24 TR 26 VG 24
>.hash{.substr(0,2).uc};
s/(.**4)(.+)/$1$0/;
return .subst(:g, /\D/, { :36(~$_) }) % 97 == 1;
}
say "$_ is {$_ ~~ IBAN ?? 'valid' !! 'invalid' }" for
'GB82 WEST 1234 5698 7654 32',
'gb82 west 1234 5698 7654 32',
'GB82 TEST 1234 5698 7654 32';

48
Task/IBAN/Perl/iban.pl Normal file
View file

@ -0,0 +1,48 @@
#!/usr/bin/perl
use strict ;
use warnings ;
use Math::BigInt ;
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 ) ;
sub validate_iban {
my $ibanstring = shift ;
$ibanstring =~ s/\s+//g ;
return 0 unless $ibanstring =~ /[0-9a-zA-Z]+/ ;
$ibanstring = uc $ibanstring ;
return 0 if ( not exists $countrycodelengths{ substr( $ibanstring , 0 , 2 ) } );
return 0 if length ( $ibanstring ) != $countrycodelengths{ substr( $ibanstring , 0 , 2 ) } ;
$ibanstring =~ s/(.{4})(.+)/$2$1/ ;
$ibanstring =~ s/([A-Z])/ord( $1 ) - 55/eg ;
my $number = Math::BigInt->new( $ibanstring ) ;
if ( $number->bmod( 97 ) == 1 ) {
return 1 ;
}
else {
return 0 ;
}
}
if ( validate_iban( "GB82 WEST 1234 5698 7654 32" ) ) {
print "GB82 WEST 1234 5698 7654 32 is a valid IBAN number!\n" ;
}
else {
print "Sorry! GB82 WEST 1234 5698 7654 32 is not valid!\n" ;
}
if ( validate_iban( "GB82TEST12345698765432" ) ) {
print "GB82TEST12345698765432 is valid!\n" ;
}

30
Task/IBAN/PicoLisp/iban.l Normal file
View file

@ -0,0 +1,30 @@
(setq *Sizes '((GB . 22) (CH . 21) (SA . 24)))
(de iban (Str)
(let Lst
(filter
'((X) (not (sp? X)))
(chop (uppc Str)) )
(when
(=
(cdr (assoc (pack (head 2 Lst)) *Sizes))
(length Lst) )
(%
(format
(mapcar
'((X)
(if (upp? X)
(- (char X) 55)
X ) )
(append (nth Lst 5) (head 4 Lst)) ) )
97 ) ) ) )
(for I '("sa03 8000 0000 6080 1016 7519"
"CH9300762011623852957"
"gb82west1234 56987654 32"
"GB82WEST000")
(if (= 1 (iban I))
(println 'Valid)
(println 'Invalid) ) )
(bye)

28
Task/IBAN/Python/iban.py Normal file
View file

@ -0,0 +1,28 @@
import re
_country2length = dict(
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 )
def valid_iban(iban):
# Ensure upper alphanumeric input.
iban = iban.replace(' ','').replace('\t','')
if not re.match(r'^[\dA-Z]+$', iban):
return False
# Validate country code against expected length.
if len(iban) != _country2length[iban[:2]]:
return False
# Shift and convert.
iban = iban[4:] + iban[:4]
digits = int(''.join(str(int(ch, 36)) for ch in iban)) #BASE 36: 0..9,A..Z -> 0..35
return digits % 97 == 1
if __name__ == '__main__':
for account in ["GB82 WEST 1234 5698 7654 32", "GB82 TEST 1234 5698 7654 32"]:
print('%s validation is: %s' % (account, valid_iban(account)))

1
Task/IBAN/README Normal file
View file

@ -0,0 +1 @@
Data source: http://rosettacode.org/wiki/IBAN

View file

@ -0,0 +1,47 @@
/*REXX program validates an IBAN (International Bank Account Number). */
@. =
@.1 = 'GB82 WEST 1234 5698 7654 32 '
@.2 = 'Gb82 West 1234 5698 7654 32 '
@.3 = 'GB82 TEST 1234 5698 7654 32 '
@.4 = 'GR16 0110 1250 0000 0001 2300 695 '
@.5 = 'GB29 NWBK 6016 1331 9268 19 '
@.6 = 'SA03 8000 0000 6080 1016 7519 '
@.7 = 'CH93 0076 2011 6238 5295 7 '
@.8 = 'IL62 0108 0000 0009 9999 999 '
@.9 = 'IL62-0108-0000-0009-9999-999 '
@.10 = 'US12 3456 7890 0987 6543 210 '
@.11 = 'GR16 0110 1250 0000 0001 2300 695X '
parse arg @.0 /*get optional first argument.*/
do k=0+(arg()==0) while @.k\=='' /*either: 0 or 1──►n*/
r = validateIBAN(@.k)
if r==0 then say ' valid IBAN:' @.k
else say 'invalid IBAN:' @.k " " r
if k==0 then leave /*if user specified IBAN, we done*/
end /*k*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────VALIDATEIBAN subroutine───────────────────────────────*/
valIdateIBAN: procedure; arg x; numeric digits 200 /*allow big #s*/
x=space(x,0); L=length(x) /*elide blanks, determine length.*/
cc = 'AD 24 AE 23 AL 28 AT 20 AZ 28 BA 20 BE 16 BG 22 BH 22 BR 29 CH 21',
'CR 21 CY 28 CZ 24 DE 22 DK 18 DO 28 EE 20 ES 24 FI 18 FO 18 FR 27',
'GB 22 GE 22 GI 23 GL 18 GR 27 GT 28 HR 21 HU 28 IE 22 IL 23 IS 26',
'IT 27 KW 30 KZ 20 LB 28 LI 21 LT 20 LU 20 LV 21 MC 27 MD 24 ME 22',
'MK 19 MR 27 MT 31 MU 30 NL 18 NO 15 PK 24 PL 28 PS 29 PT 25 RO 24',
'RS 22 SA 24 SE 24 SI 19 SK 24 SM 27 TN 24 TR 26 VG 24' /*country,L*/
@abc# = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' /*alphabet & decimal digs*/
cc_=left(x,2); kk=substr(x,3,2) /*get IBAN country code, checkDig*/
c#=wordpos(cc_,cc) /*find the country code index. */
if c#==0 then return '***error!*** invalid country code:' cc_
if \datatype(x,'A') then return '***error!*** invalid character:',
substr(x,verify(x,@abc#),1)
cL=word(cc,c#+1) /*get length of country's IBAN. */
if cL\==L then return '***error!*** invalid IBAN length:' L ' (should be' cL")"
y=substr(x,5)left(x,4) /*put 4 in front ───► the back. */
z= /*translate characters──►digits. */
do j=1 for L; _=substr(y,j,1)
if datatype(_,'U') then z=z || pos(_,@abc#)+9
else z=z || _
end /*j*/
if z//97==1 then return 0 /*check to see if correct modulus*/
return '***error!*** invalid check digits.'

View file

@ -0,0 +1,56 @@
/*REXX program validates an IBAN (International Bank Account Number). */
@. =
@.1 = 'GB82 WEST 1234 5698 7654 32 '
@.2 = 'Gb82 West 1234 5698 7654 32 '
@.3 = 'GB82 TEST 1234 5698 7654 32 '
@.4 = 'GR16 0110 1250 0000 0001 2300 695 '
@.5 = 'GB29 NWBK 6016 1331 9268 19 '
@.6 = 'SA03 8000 0000 6080 1016 7519 '
@.7 = 'CH93 0076 2011 6238 5295 7 '
@.8 = 'IL62 0108 0000 0009 9999 999 '
@.9 = 'IL62-0108-0000-0009-9999-999 '
@.10 = 'US12 3456 7890 0987 6543 210 '
@.11 = 'GR16 0110 1250 0000 0001 2300 695X '
@.12 = 'GT11 2222 3333 4444 5555 6666 7777 '
@.13 = 'MK11 2222 3333 4444 555 '
parse arg @.0 /*get optional first argument.*/
do k=0+(arg()==0) while @.k\=='' /*either: 0 or 1──►n*/
r = validateIBAN(@.k)
if r==0 then say ' valid IBAN:' @.k
else say 'invalid IBAN:' @.k " " r
if k==0 then leave /*if user specified IBAN, we done*/
end /*k*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────VALIDATEIBAN subroutine───────────────────────────────────────────────────────────────*/
valIdateIBAN: procedure; arg x; numeric digits 200 /*allow big #s*/
x=space(x,0); L=length(x) /*elide blanks, determine length.*/
cc = 'AD 24 AE 23 AL 28 AT 20 AZ 28 BA 20 BE 16 BG 22 BH 22 BR 29 CH 21',
'CR 21 CY 28 CZ 24 DE 22 DK 18 DO 28 EE 20 ES 24 FI 18 FO 18 FR 27',
'GB 22 GE 22 GI 23 GL 18 GR 27 GT 28 HR 21 HU 28 IE 22 IL 23 IS 26',
'IT 27 KW 30 KZ 20 LB 28 LI 21 LT 20 LU 20 LV 21 MC 27 MD 24 ME 22',
'MK 19 MR 27 MT 31 MU 30 NL 18 NO 15 PK 24 PL 28 PS 29 PT 25 RO 24',
'RS 22 SA 24 SE 24 SI 19 SK 24 SM 27 TN 24 TR 26 VG 24' /*country,L*/
@abc# = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' /*alphabet & decimal digs*/
cc_=left(x,2); kk=substr(x,3,2) /*get IBAN country code, checkDig*/
c#=wordpos(cc_,cc) /*find the country code index. */
if c#==0 then return '***error!*** invalid country code:' cc_
if \datatype(x,'A') then return '***error!*** invalid character:',
substr(x,verify(x,@abc#),1)
cL=word(cc,c#+1) /*get length of country's IBAN. */
if cL\==L then return '***error!*** invalid IBAN length:' L ' (should be' cL")"
if cc_=='BR' & date("S")<20130701 then return "***error!*** invalid IBAN country, Brazil isn't valid until 1-July-2013."
if cc_=='GT' & date("S")<20140701 then return "***error!*** invalid IBAN country, Guatemala isn't valid until 1-July-2014."
if cc_=='BA' & kk\==39 then return "***error!*** invalid check digits for Bosnia and Herzegovina:" kk
if cc_=='MK' & kk\==07 then return "***error!*** invalid check digits for Macedonia:" kk
if cc_=='ME' & kk\==25 then return "***error!*** invalid check digits for Montenegro:" kk
if cc_=='PT' & kk\==50 then return "***error!*** invalid check digits for Portugal:" kk
if cc_=='SI' & kk\==56 then return "***error!*** invalid check digits for Slovenia:" kk
y=substr(x,5)left(x,4) /*put 4 in front ───► the back. */
z= /*translate characters──►digits. */
do j=1 for L; _=substr(y,j,1)
if datatype(_,'U') then z=z || pos(_,@abc#)+9
else z=z || _
end /*j*/
if z//97==1 then return 0 /*check to see if correct modulus*/
return '***error!*** invalid check digits.'

25
Task/IBAN/Racket/iban.rkt Normal file
View file

@ -0,0 +1,25 @@
#lang racket
(define lens
'([AL 28] [AD 24] [AT 20] [AZ 28] [BH 22] [BE 16] [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]))
(define (valid-iban? str)
(define str* (regexp-replace* #px"\\s+" str ""))
(define c (cond [(regexp-match #rx"^[A-Z][A-Z]" str*)
=> (λ(x) (assq (string->symbol (car x)) lens))]
[else #f]))
(define (letter c)
(number->string (+ (char->integer (string-ref c 0)) -65 10)))
(and c (= (cadr c) (string-length str*))
(regexp-match? #rx"[A-Z0-9]" str*)
(let* ([x (string-append (substring str* 4) (substring str* 0 4))]
[x (string->number (regexp-replace* #rx"[A-Z]" x letter))])
(= 1 (modulo x 97)))))
(valid-iban? "GB82 WEST 1234 5698 7654 32") ; => #t
(valid-iban? "GB82 TEST 1234 5698 7654 32") ; => #f

29
Task/IBAN/Ruby/iban.rb Normal file
View file

@ -0,0 +1,29 @@
def valid_iban? iban
len = {
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
}
# Ensure upper alphanumeric input.
iban.delete! " \t"
return false unless iban =~ /^[\dA-Z]+$/
# Validate country code against expected length.
cc = iban[0, 2].to_sym
return false unless iban.size == len[cc]
# Shift and convert.
iban = iban[4..-1] + iban[0, 4]
iban.gsub!(/./) { |c| c.to_i(36) }
iban.to_i % 97 == 1
end
p valid_iban? "GB82 WEST 1234 5698 7654 32" #=> true
p valid_iban? "GB82 TEST 1234 5698 7654 32" #=> false

View file

@ -0,0 +1,45 @@
import scala.collection.immutable.SortedMap
class Iban(val iban: String) {
// Isolated tests
def isAllUpperCase = iban.toUpperCase == iban
def isValidpattern = (Iban.pattern findFirstIn iban).nonEmpty
def isNationalSize = {
Iban.ccVsLength.getOrElse(iban.take(2), 0) == iban.size
}
def isCheckNumberOK = {
def rearrange = (iban.drop(4) + iban.take(4)). // Move left country code part to end
// continue with each char converted to Int
map(ch => if (ch.isDigit) ch.toInt - '0' else ch - 'A' + 10).mkString
(BigInt(rearrange) mod 97) == 1
}
def isValidIban = {
isAllUpperCase &&
isValidpattern &&
isNationalSize &&
isCheckNumberOK
}
}
object Iban {
// IBAN length database
lazy val ccVsLength: SortedMap[String, Int] = SortedMap[String, Int]() ++
"""AD24 AE23 AL28 AO25 AT20 AZ28 BA20 BE16 BF27 BG22 BH22 BI16
|BJ28 BR29 CG27 CH21 CI28 CM27 CR21 CV25 CY28 CZ24 DE22 DK18
|DO28 DZ24 EE20 EG27 ES24 FI18 FO18 FR27 GA27 GB22 GE22 GI23
|GL18 GR27 GT28 HR21 HU28 IE22 IL23 IR26 IS26 IT27 JO30 KW30
|KZ20 LB28 LI21 LT20 LU20 LV21 MC27 MD24 ME22 MG27 MK19 ML28
|MR27 MT31 MU30 MZ25 NL18 NO15 PK24 PL28 PS29 PT25 QA29 RO24
|RS22 SA24 SE24 SI19 SK24 SM27 SN28 TN24 TR26 UA29 VG24""".
stripMargin.replaceAll( """\s""", " ").split(' ').
map(v => (v.take(2), if (v.isEmpty) 0 else v.slice(2, 4).toInt))
lazy val pattern = "([A-Z]{2})([0-9]{2})([A-Z0-9]{4})([A-Z0-9]{0,2})([0-9]{7})(([A-Z0-9]?){0,16})".r
def apply(s: String) = new Iban(s.replaceAll( """\s""", ""))
}

View file

@ -0,0 +1,98 @@
object IbanTest extends App {
def blackCases = """AT611904300235473201
|GB82TEST12345698765432
|GB81WEST12345698765432""".stripMargin
def whiteCases = """AD1200012030200359100100
|AE26 0211 0000 0023 0064 016
|AL47 2121 1009 0000 0002 3569 8741
|AO06000600000100037131174
|AZ21NABZ00000000137010001944
|BA391290079401028494
|BE68539007547034
|BF1030134020015400945000643
|BG80BNBG96611020345678
|BH29BMAG1299123456BH00
|BI43201011067444
|BJ11B00610100400271101192591
|BR9700360305000010009795493P1
|CG5230011000202151234567890
|CH9300762011623852957
|CI05A00060174100178530011852
|CM2110003001000500000605306
|CR0515202001026284066
|CV64000300004547069110176
|CY17002001280000001200527600
|CZ6508000000192000145399
|DE89370400440532013000
|DK5000400440116243
|DO28BAGR00000001212453611324
|DZ4000400174401001050486
|EE382200221020145685
|EG1100006001880800100014553
|ES9121000418450200051332
|FI2112345600000785
|FO1464600009692713
|FR1420041010050500013M02606
|FR7630007000110009970004942
|GA2140002000055602673300064
|GB29NWBK60161331926819
|GE29NB0000000101904917
|GI75NWBK000000007099453
|GL8964710001000206
|GR1601101250000000012300695
|GT82TRAJ01020000001210029690
|HR1210010051863000160
|HU42117730161111101800000000
|IE29AIBK93115212345678
|IL620108000000099999999
|IR580540105180021273113007
|IS140159260076545510730339
|IT60X0542811101000000123456
|JO94CBJO0010000000000131000302
|KW74NBOK0000000000001000372151
|KZ176010251000042993
|LB30099900000001001925579115
|LI21088100002324013AA
|LT121000011101001000
|LU280019400644750000
|LV80BANK0000435195001
|MC5813488000010051108001292
|MD24AG000225100013104168
|ME25505000012345678951
|MG4600005030010101914016056
|MK07300000000042425
|ML03D00890170001002120000447
|MR1300012000010000002037372
|MT84MALT011000012345MTLCAST001S
|MU17BOMM0101101030300200000MUR
|MZ59000100000011834194157
|NL91ABNA0417164300
|NL81 TRIO 0212 4710 66
|NO9386011117947
|PK24SCBL0000001171495101
|PL27114020040000300201355387
|PS92PALS000000000400123456702
|PT50000200000163099310355
|PT50000201231234567890154
|QA58 DOHB 0000 1234 5678 90AB CDEF G
|RO49 AAAA 1B31 0075 9384 0000
|RS35260005601001611379
|SA0380000000608010167519
|SE3550000000054910000003
|SI56191000000123438
|SK3112000000198742637541
|SM86U0322509800000000270100
|SN12K00100152000025690007542
|TN5914207207100707129648
|TR330006100519786457841326
|UA57 3543 4700 0676 2462 0549 2502 6
|VG96 VPVG 0000 0123 4567 8901
|GB82 WEST 1234 5698 7654 32
|SA03 8000 0000 6080 1016 7519
|CH93 0076 2011 6238 5295 7""".stripMargin
whiteCases.lines.foreach(l => assert(Iban(l).isValidIban))
blackCases.lines.foreach(l => assert(!Iban(l).isValidIban))
println(s"Successfully completed; ${whiteCases.lines.size + blackCases.lines.size} cases tested, no errors.")
}

View file

@ -0,0 +1,57 @@
$ include "seed7_05.s7i";
include "bigint.s7i";
const type: countryHash is hash [string] integer;
const func countryHash: initCountryCode is func
result
var countryHash: cc is countryHash.value;
begin
cc @:= ["AL"] 28; cc @:= ["AD"] 24; cc @:= ["AT"] 20; cc @:= ["AZ"] 28; cc @:= ["BE"] 16; cc @:= ["BH"] 22;
cc @:= ["BA"] 20; cc @:= ["BR"] 29; cc @:= ["BG"] 22; cc @:= ["CR"] 21; cc @:= ["HR"] 21; cc @:= ["CY"] 28;
cc @:= ["CZ"] 24; cc @:= ["DK"] 18; cc @:= ["DO"] 28; cc @:= ["EE"] 20; cc @:= ["FO"] 18; cc @:= ["FI"] 18;
cc @:= ["FR"] 27; cc @:= ["GE"] 22; cc @:= ["DE"] 22; cc @:= ["GI"] 23; cc @:= ["GR"] 27; cc @:= ["GL"] 18;
cc @:= ["GT"] 28; cc @:= ["HU"] 28; cc @:= ["IS"] 26; cc @:= ["IE"] 22; cc @:= ["IL"] 23; cc @:= ["IT"] 27;
cc @:= ["KZ"] 20; cc @:= ["KW"] 30; cc @:= ["LV"] 21; cc @:= ["LB"] 28; cc @:= ["LI"] 21; cc @:= ["LT"] 20;
cc @:= ["LU"] 20; cc @:= ["MK"] 19; cc @:= ["MT"] 31; cc @:= ["MR"] 27; cc @:= ["MU"] 30; cc @:= ["MC"] 27;
cc @:= ["MD"] 24; cc @:= ["ME"] 22; cc @:= ["NL"] 18; cc @:= ["NO"] 15; cc @:= ["PK"] 24; cc @:= ["PS"] 29;
cc @:= ["PL"] 28; cc @:= ["PT"] 25; cc @:= ["RO"] 24; cc @:= ["SM"] 27; cc @:= ["SA"] 24; cc @:= ["RS"] 22;
cc @:= ["SK"] 24; cc @:= ["SI"] 19; cc @:= ["ES"] 24; cc @:= ["SE"] 24; cc @:= ["CH"] 21; cc @:= ["TN"] 24;
cc @:= ["TR"] 26; cc @:= ["AE"] 23; cc @:= ["GB"] 22; cc @:= ["VG"] 24;
end func;
const countryHash: countryCode is initCountryCode;
const func boolean: isLegal (in var string: iban) is func
result
var boolean: legal is FALSE;
local
var char: ch is ' ';
var string: converted is "";
begin
iban := upper(replace(iban, " ", ""));
legal := iban[.. 2] in countryCode and countryCode[iban[.. 2]] = length(iban);
iban := iban[5 ..] & iban[.. 4];
for ch range iban do
case ch of
when {'0' .. '9'}: converted &:= ch;
when {'A' .. 'Z'}: converted &:= str(ord(ch) - ord('A') + 10);
otherwise: legal := FALSE;
end case;
end for;
legal := legal and (bigInteger parse converted) rem 97_ = 1_;
end func;
const proc: check (in string: iban) is func
begin
writeln("Valid " <& iban <& ": " <& isLegal(iban));
end func;
const proc: main is func
begin
check("GB82 WEST 1234 5698 7654 32");
check("GB82WEST12345698765432");
check("gb82 west 1234 5698 7654 32");
check("GB82 TEST 1234 5698 7654 32");
check("GB82 WEST 1243 5698 7654 32");
end func;

34
Task/IBAN/Tcl/iban-1.tcl Normal file
View file

@ -0,0 +1,34 @@
proc verifyIBAN {iban} {
# Normalize by up-casing and stripping illegal chars (e.g., space)
set iban [regsub -all {[^A-Z0-9]+} [string toupper $iban] ""]
# Get the expected length from the country-code part
switch [string range $iban 0 1] {
NO { set len 15 }
BE { set len 16 }
DK - FI - FO - GL - NL { set len 18}
MK - SI { set len 19 }
AT - BA - EE - KZ - LT - LU { set len 20 }
CH - CR - HR - LI - LV { set len 21 }
BG - BH - DE - GB - GE - IE - ME - RS { set len 22 }
AE - GI - IL { set len 23 }
AD - CZ - ES - MD - PK - RO - SA - SE - SK - TN - VG { set len 24 }
PT { set len 25 }
IS - TR { set len 26 }
FR - GR - IT - MC - MR - SM { set len 27 }
AL - AZ - CY - DO - GT - HU - LB - PL { set len 28 }
BR - PS { set len 29 }
KW - MU { set len 30 }
MT { set len 31 }
default {
# unsupported country code
return false
}
}
# Convert to number
set num [string map {
A 10 B 11 C 12 D 13 E 14 F 15 G 16 H 17 I 18 J 19 K 20 L 21 M 22
N 23 O 24 P 25 Q 26 R 27 S 28 T 29 U 30 V 31 W 32 X 33 Y 34 Z 35
} [string range $iban 4 end][string range $iban 0 3]]
# Verify length and modulus
return [expr {[string length $iban] == $len && $num % 97 == 1}]
}

4
Task/IBAN/Tcl/iban-2.tcl Normal file
View file

@ -0,0 +1,4 @@
set iban "GB82 WEST 1234 5698 7654 32"
puts "$iban is [expr {[verifyIBAN $iban] ? {verified} : {unverified}}]"
set not "GB42 WEST 1234 5698 7654 32"
puts "$not is [expr {[verifyIBAN $not] ? {verified} : {unverified}}]"

View file

@ -0,0 +1,34 @@
declare -A base36=(
[A]=10 [B]=11 [C]=12 [D]=13 [E]=14 [F]=15 [G]=16 [H]=17 [I]=18
[J]=19 [K]=20 [L]=21 [M]=22 [N]=23 [O]=24 [P]=25 [Q]=26 [R]=27
[S]=28 [T]=29 [U]=30 [V]=31 [W]=32 [X]=33 [Y]=34 [Z]=35
)
function is_iban {
local -u acct=${1//[^[:alnum:]]/}
acct=${acct:4}${acct:0:4}
local i char digits=""
for ((i=0; i<${#acct}; i++)); do
char=${acct:i:1}
digits+=${base36[$char]:-$char}
done
local mod=$(mod97 $digits)
(( mod == 1 ))
}
function mod97 {
local D=$1
N=${D:0:9}
D=${D:9}
while [[ -n $D ]]; do
mod=$(( N % 97 ))
N=$(printf "%02d%s" $mod ${D:0:7})
D=${D:7}
done
echo $(( N % 97 ))
}
for test in "GB82 WEST 1234 5698 7654 32" "GB42 WEST 1234 5698 7654 32"; do
printf "%s : " "$test"
is_iban "$test" && echo yes || echo no
done