September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -1,8 +1,20 @@
{{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 &nbsp; [[wp:International_Bank_Account_Number|International Bank Account Number (IBAN)]] &nbsp; is an internationally agreed means of identifying bank accounts across national borders with a reduced risk of propagating [[wp:Transcription_error|transcription errors]].
The IBAN consists of up to '''34''' alphanumeric characters:
::* &nbsp; first the two-letter ISO 3166-1 alpha-2 country code,
::* &nbsp; then two check digits, and
::* &nbsp; finally a country-specific Basic Bank Account Number (BBAN).
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>.
;Task:
Validate the following fictitious IBAN: &nbsp; <tt> GB82 WEST 1234 5698 7654 32 </tt>
Details of the algorithm can be found on the Wikipedia page.
<br><br>

View file

@ -2,36 +2,40 @@ 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 "
private static final String DEFSTRS = ""
+ "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";
private static final Map<String, Integer> DEFINITIONS = new HashMap<>();
static {
isoPairs = new HashMap<>();
for (String p : iso.split(" "))
isoPairs.put(p.substring(0, 2), Integer.parseInt(p.substring(2)));
for (String definition : DEFSTRS.split(" "))
DEFINITIONS.put(definition.substring(0, 2), Integer.parseInt(definition.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));
String[] ibans = {
"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",
"XX00 0000",
"",
"DE",
"DE13 äöü_ 1234 1234 1234 12"};
for (String iban : ibans)
System.out.printf("%s is %s.%n", iban, validateIBAN(iban) ? "valid" : "not valid");
}
static boolean validateIBAN(String iban) {
iban = iban.replaceAll("\\s", "").toUpperCase();
iban = iban.replaceAll("\\s", "").toUpperCase(Locale.ROOT);
int len = iban.length();
if (len < 4 || isoPairs.get(iban.substring(0, 2)) != len)
if (len < 4 || !iban.matches("[0-9A-Z]+") || DEFINITIONS.getOrDefault(iban.substring(0, 2), 0) != len)
return false;
iban = iban.substring(4) + iban.substring(0, 4);
@ -42,6 +46,6 @@ public class IBAN {
BigInteger bigInt = new BigInteger(sb.toString());
return bigInt.mod(new BigInteger("97")).intValue() == 1;
return bigInt.mod(BigInteger.valueOf(97)).intValue() == 1;
}
}

View file

@ -0,0 +1,28 @@
# v0.6.0
function validiban(iban::String)
const 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
)
# Ensure upper alphanumeric input.
iban = replace(iban, " ", "")
iban = replace(iban, "\t", "")
rst = ismatch(r"^[\dA-Z]+$", iban)
# Validate country code against expected length.
rst = rst && length(iban) == COUNTRY2LENGTH[iban[1:2]]
# Shift and convert.
iban = iban[5:end] * iban[1:4]
digits = parse(BigInt, join(string(parse(Int, ch, 36)) for ch in iban))
return rst && digits % 97 == 1
end
@show validiban("GB82 WEST 1234 5698 7654 32")
@show validiban("GB82 TEST 1234 5698 7654 32")

View file

@ -0,0 +1,40 @@
// version 1.0.6
import java.math.BigInteger
object Iban {
/* List updated to release 73, January 2017, of IBAN Registry (75 countries) */
private val countryCodes =
"AD24 AE23 AL28 AT20 AZ28 BA20 BE16 BG22 BH22 BR29 BY28 CH21 CR22 CY28 CZ24 DE22 " +
"DK18 DO28 EE20 ES24 FI18 FO18 FR27 GB22 GE22 GI23 GL18 GR27 GT28 HR21 HU28 IE22 " +
"IL23 IQ23 IS26 IT27 JO30 KW30 KZ20 LB28 LC32 LI21 LT20 LU20 LV21 MC27 MD24 ME22 " +
"MK19 MR27 MT31 MU30 NL18 NO15 PK24 PL28 PS29 PT25 QA29 RO24 RS22 SA24 SC31 SE24 " +
"SI19 SK24 SM27 ST25 SV28 TL23 TN24 TR26 UA29 VG24 XK20"
private fun checkCountryCode(cc: String) = cc in countryCodes
fun validate(iban: String): Boolean {
// remove spaces from IBAN
var s = iban.replace(" ", "")
// check country code
if (!checkCountryCode(s.substring(0, 2) + s.length)) return false
// move first 4 characters to end
s = s.substring(4) + s.substring(0, 4)
// replace A to Z with numbers 10 To 35
for (ch in 'A'..'Z') s = s.replace(ch.toString(), (ch - 55).toInt().toString())
// check whether mod 97 calculation gives a remainder of 1
return BigInteger(s) % BigInteger.valueOf(97L) == BigInteger.ONE
}
}
fun main(args: Array<String>) {
val ibans = arrayOf("GB82 WEST 1234 5698 7654 32", "GB82 TEST 1234 5698 7654 32")
for (iban in ibans) {
val isValid = Iban.validate(iban)
println(iban + if(isValid) " may be valid" else " is not valid")
}
}

59
Task/IBAN/Phix/iban.phix Normal file
View file

@ -0,0 +1,59 @@
--
-- demo\rosetta\IBAN.exw
-- =====================
--
constant nations = {{"AD",24}, -- Andorra
-- (full list in distro)
{"CH",21}, -- Switzerland
{"GB",22}, -- United Kingdom
{"SA",24}, -- Saudi Arabia
{"XK",20}} -- Kosovo
constant {countries,lengths} = columnize(nations)
function iban(string code)
-- This routine does and should reject codes containing spaces etc.
-- Use iban_s() below for otherwise.
integer country = find(code[1..2],countries)
if country!=0
and length(code)=lengths[country] then
code = code[5..$]&code[1..4]
integer c = 0
for i=1 to length(code) do
integer ch=code[i]
if ch>='0' and ch<='9' then
c = c*10+ch-'0'
elsif ch>='A' and ch<='Z' then
c = c*100+ch-55
else
return false
end if
c = mod(c,97)
end for
return c=1
end if
return false
end function
function iban_s(string code)
-- strips any embedded spaces and hyphens before validating.
code = substitute_all(code,{" ","-"},{"",""})
return iban(code)
end function
procedure test(string code, bool expected)
bool valid = iban_s(code)
string state
if valid=expected then
state = iff(valid?"ok":"invalid (as expected)")
else
state = iff(valid?"OK!!":"INVALID!!")&" (NOT AS EXPECTED)"
end if
printf(1,"%-34s :%s\n",{code,state})
end procedure
test("GB82 WEST 1234 5698 7654 32",true)
test("GB82 TEST 1234 5698 7654 32",false)
test("GB81 WEST 1234 5698 7654 32",false)
test("SA03 8000 0000 6080 1016 7519",true)
test("CH93 0076 2011 6238 5295 7",true)

65
Task/IBAN/Rust/iban.rust Normal file
View file

@ -0,0 +1,65 @@
fn main() {
for iban in [
"",
"x",
"QQ82",
"QQ82W",
"GB82 TEST 1234 5698 7654 322",
"gb82 WEST 1234 5698 7654 32",
"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",
].iter()
{
println!(
"'{}' is {}valid",
iban,
if validate_iban(iban) { "" } else { "NOT " }
);
}
}
fn validate_iban(iban: &str) -> bool {
let iso_len = [
("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),
];
let trimmed_iban = iban.chars()
.filter(|&ch| ch != ' ')
.collect::<String>()
.to_uppercase();
if trimmed_iban.len() < 4 {
return false;
}
let prefix = &trimmed_iban[0..2];
if let Some(pair) = iso_len.iter().find(|&&(code, _)| code == prefix) {
if pair.1 != trimmed_iban.len() {
return false;
}
} else {
return false;
}
let reversed_iban = format!("{}{}", &trimmed_iban[4..], &trimmed_iban[0..4]);
let mut expanded_iban = String::new();
for ch in reversed_iban.chars() {
expanded_iban.push_str(&if ch.is_numeric() {
format!("{}", ch)
} else {
format!("{}", ch as u8 - 'A' as u8 + 10u8)
});
}
expanded_iban.bytes().fold(0, |acc, ch| {
(acc * 10 + ch as u32 - '0' as u32) % 97
}) == 1
}

View file

@ -1,5 +1,5 @@
func valid_iban(iban) {
static len = Hash.new(
static len = Hash(
AD=>24, AE=>23, AL=>28, AO=>25, AT=>20, AZ=>28, BA=>20, BE=>16, BF=>27,
BG=>22, BH=>22, BI=>16, BJ=>28, BR=>29, CG=>27, CH=>21, CI=>28, CM=>27,
CR=>21, CV=>25, CY=>28, CZ=>24, DE=>22, DK=>18, DO=>28, DZ=>24, EE=>20,
@ -10,22 +10,22 @@ func valid_iban(iban) {
MZ=>25, NL=>18, NO=>15, PK=>24, PL=>28, PS=>29, PT=>25, QA=>29, RO=>24,
RS=>22, SA=>24, SE=>24, SI=>19, SK=>24, SM=>27, SN=>28, TN=>24, TR=>26,
UA=>29, VG=>24,
);
)
# Ensure upper alphanumeric input.
iban -= /\s+/g;
iban.uc! ~~ /^[0-9A-Z]+\z/ || return false;
iban -= /\s+/g
iban.uc! ~~ /^[0-9A-Z]+\z/ || return false
# Validate country code against expected length.
var cc = iban.substr(0, 2);
iban.len == len{cc} || return false;
var cc = iban.substr(0, 2)
iban.len == len{cc} || return false
# Shift and convert.
iban.sub!(/(.{4})(.+)/, {|a,b| b+a});
iban.gsub!(/([A-Z])/, {|a| a.ord - 55});
iban.sub!(/(.{4})(.+)/, {|a,b| b+a})
iban.gsub!(/([A-Z])/, {|a| a.ord - 55})
iban.to_i % 97 == 1;
iban.to_i % 97 == 1
}
say valid_iban("GB82 WEST 1234 5698 7654 32"); #=> true
say valid_iban("GB82 TEST 1234 5698 7654 32"); #=> false
say valid_iban("GB82 WEST 1234 5698 7654 32") #=> true
say valid_iban("GB82 TEST 1234 5698 7654 32") #=> false

View file

@ -0,0 +1,67 @@
(* country_code : string -> int *)
(* Get the length of a valid IBAN given the two chars long country code *)
fun country_code (str : string) : int =
case str of
"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
| _ => raise Domain
(* removespace : string -> string *)
(* Removes all spaces from a string *)
fun removespace s = String.translate (fn #" " => "" | c => str c) s
(* to_upper : string -> string *)
(* Convert every char to upper of a string *)
fun to_upper (s : string) : string =
String.translate (fn c => str (Char.toUpper c)) s
(* convert_to_number : char -> string *)
(* Covert a alphanumeric char into a numerical string *)
fun convert_to_number (c : char) : string =
if Char.isDigit c then str c else
if Char.isUpper c then Int.toString (10 + ord c - ord #"A") else
raise Domain
(* verify_iban : string -> bool *)
(* Check weather a string is a valid IBAN *)
fun verify_iban str =
let
(* Remove spaces and make upper case *)
val str = to_upper (removespace str)
(* Fetch first two chars (country code) *)
val country = String.substring (str, 0, 2)
val len = country_code country
in
(* size test *)
String.size str = len
andalso
(* Every char must be alphanumeric *)
List.all Char.isAlphaNum (explode str)
andalso
let
(* Reorder *)
val str = String.substring (str, 4, String.size str - 4) ^ String.substring (str, 0, 4)
(* Convert into digits *)
val str = String.translate convert_to_number str
(* Convert into a big number *)
val number = valOf (IntInf.fromString str)
in
IntInf.mod (number, 97) = 1
end
end handle Subscript => false | Domain => false

View file

@ -0,0 +1,64 @@
10 REM REM Used the following as official standard:
20 REM REM http://www.cnb.cz/cs/platebni_styk/iban/download/EBS204.pdf
30 REM REM Pairs of ISO 3166 country code & expected IBAN length for this country
40 LET c$="AL28 AD24 AT20 AZ28 BE16 BH22 BA20 BR29 BG22 CR21 HR21 CY28 CZ24 DK18 DO28 EE20 "
50 LET c$=c$+"FO18 FI18 FR27 GE22 DE22 GI23 GR27 GL18 GT28 HU28 IS26 IE22 IL23 IT27 KZ20 KW30 "
60 LET c$=c$+"LV21 LB28 LI21 LT20 LU20 MK19 MT31 MR27 MU30 MC27 MD24 ME22 NL18 NO15 PK24 PS29 "
70 LET c$=c$+"PL28 PT25 RO24 SM27 SA24 RS22 SK24 SI19 ES24 SE24 CH21 TN24 TR26 AE23 GB22 VG24 "
80 LET e$=""
100 LET i$="GB82 WEST 1234 5698 7654 32": GO SUB 1000
110 LET i$="gb82 west 1234 5698 7654 32": GO SUB 1000
120 LET i$="GB82 TEST 1234 5698 7654 32": GO SUB 1000
130 LET i$="GR16 0110 1250 0000 0001 2300 695": GO SUB 1000
140 LET i$="IL62-0108-0000-0009-9999-999": GO SUB 1000
900 STOP
1000 REM IBAN check routine
1010 LET explen=0: LET lenc=LEN c$
1020 FOR i=1 TO lenc STEP 5
1030 IF i$( TO 2)=c$(i TO i+1) THEN LET explen=VAL c$(i+2 TO i+3): GO TO 2000
1040 NEXT i
2000 LET match=explen>0
2010 REM Continue if country code found
2020 IF NOT match THEN LET e$="country code: "+i$( TO 2): GO TO 3000
2030 REM Remove espace = convert to digital IBAN
2040 LET d$=""
2050 FOR i=1 TO LEN i$
2060 IF i$(i)>" " THEN LET d$=d$+i$(i)
2070 NEXT i
2080 LET match=explen=LEN d$
2090 REM Continue if length is correct
2100 IF NOT match THEN LET e$="code length, expected length: "+STR$ explen: GO TO 3000
2110 REM Create temporary string with country code appended
2120 LET t$=d$(5 TO )+d$(1 TO 2)
2130 REM Make big number, replacing letters by numbers using next conversion table: A=10 ... Z=35
2140 LET b$=""
2150 FOR i=1 TO LEN t$
2160 LET c= CODE t$(i)
2170 IF (c>64 AND c<91) THEN LET b$=b$+STR$ (c-55): GO TO 2200
2190 IF (c>47 AND c<58) THEN LET b$=b$+t$(i)
2200 NEXT i
2210 REM MOD 97 on bignum$+"00" and subtract result from 98 to obtain control number
2220 LET k$=b$+"00": GO SUB 4000
2230 LET kk=98-mod97
2240 REM Compare with control number in IBAN
2250 LET match=VAL i$(3 TO 4)=kk
2260 REM Continue if control number matches
2270 IF NOT match THEN LET e$="check digits, should be: "+STR$ kk: GO TO 3000
2280 REM Append kk to bignum$ and determine if MOD 97 results in 1
2285 LET k$="0"+STR$ kk
2290 LET k$=b$+k$(LEN k$-1 TO ): GO SUB 4000
2300 LET match=mod97=1
2310 REM Continue if mod 97
2320 IF NOT match THEN LET e$="result from modulo 97"
3000 IF match THEN PRINT " ": GO TO 3100
3010 PRINT "in";: LET e$=" ***error!*** invalid "+e$
3100 PRINT "valid IBAN: ";i$;e$: LET e$=""
3110 RETURN
4000 REM Modulo 97
4010 LET mod97=0
4020 FOR i=1 TO LEN k$
4030 LET d$=STR$ (mod97)+k$(i)
4040 LET mod97=FN m(VAL (d$),97)
4050 NEXT i
4060 RETURN
5000 DEF FN m(a,b)=a-INT (a/b)*b: REM modulo

6
Task/IBAN/Zkl/iban-1.zkl Normal file
View file

@ -0,0 +1,6 @@
var BN=Import("zklBigNum");
fcn validateIBAN(iban){
iban=iban-" \t";
alphaNums.matches(iban) and (ibans.find(iban[0,2])==iban.len()) and
( BN((iban[4,*]+iban[0,4]).apply("toInt",36)) % 97 == 1 )
}

12
Task/IBAN/Zkl/iban-2.zkl Normal file
View file

@ -0,0 +1,12 @@
fcn validateIBAN(iban){
iban=iban-" \t";
alphaNums.matches(iban) and (ibans.find(iban[0,2])==iban.len()) and
( (iban[4,*]+iban[0,4]).apply("toInt",36) : mod97(_) == 1 )
}
fcn mod97(str){
n:=0; m:=9; M:=0; while(N:=str[n,m]){
M=((M.toString()+N).toInt()) % 97;
n+=m; m=7;
}
M
}

10
Task/IBAN/Zkl/iban-3.zkl Normal file
View file

@ -0,0 +1,10 @@
var alphaNums=RegExp("^[0-9A-Z]+$");
var ibans= // Dictionary("AD":24, ...)
("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")
.split(" ").pump(D(),fcn(w){return(w[0,2],w[2,*].toInt())});

20
Task/IBAN/Zkl/iban-4.zkl Normal file
View file

@ -0,0 +1,20 @@
// all valid
T("GB82 WEST 1234 5698 7654 32","GB82WEST12345698765432",
"GR16 0110 1250 0000 0001 2300 695","GB29 NWBK 6016 1331 9268 19",
"SA03 8000 0000 6080 1016 7519","CH93 0076 2011 6238 5295 7",
"IL62 0108 0000 0009 9999 999")
.apply(validateIBAN).println();
// all invalid
T("gb82 west 1234 5698 7654 32","GB82 TEST 1234 5698 7654 32",
"GB82 WEST 1243 5698 7654 32","AE82 WEST 1234 5698 7654 32"
"IL62-0108-0000-0009-9999-999","US12 3456 7890 0987 6543 210",
"GR16 0110 1250 0000 0001 2300 695X","GT11 2222 3333 4444 5555 6666 7777",
"MK11 2222 3333 4444 555")
.apply(validateIBAN).println();
// white list from Scala
("AD1200012030200359100100 AE260211000000230064016 AL47212110090000000235698741 "
...
"CH9300762011623852957").split()
.apply(validateIBAN).toString(*).println();