Another update from ingydotnet^djgoku

This commit is contained in:
Ingy döt Net 2015-11-18 06:14:39 +00:00
parent 91df62d461
commit 948b86eafa
7604 changed files with 108452 additions and 22726 deletions

View file

@ -6,8 +6,8 @@
#include <cctype>
using namespace boost::algorithm ;
bool isValid ( const std::string &ibanstring ) {
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 } ,
@ -31,17 +31,18 @@ bool isValid ( const std::string &ibanstring ) {
return false ;
if ( teststring.length( ) != countrycodes[ teststring.substr( 0 , 2 ) ] )
return false ;
if ( ! ( all ( teststring , is_alnum( ) ) ) )
if (!all(teststring, is_alnum()))
return false ;
to_upper( teststring ) ;
teststring = teststring.append( teststring.substr( 0 , 4 ) ) ;
teststring.assign( teststring.substr( 4 ) ) ;
std::rotate(teststring.begin(), teststring.begin() + 4, teststring.end());
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 ) ;
for (const auto& c : teststring)
{
if (std::isdigit(c))
numberstring += c ;
if (std::isupper(c))
numberstring += std::to_string(static_cast<int>(c) - 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
@ -63,10 +64,14 @@ bool isValid ( const std::string &ibanstring ) {
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 ;
void SayValidity(const std::string& iban)
{
std::cout << iban << (isValid(iban) ? " is " : " is not ") << "valid\n";
}
int main( )
{
SayValidity("GB82 WEST 1234 5698 7654 32");
SayValidity("GB82TEST12345698765432");
return 0 ;
}

View file

@ -13,7 +13,7 @@
int lengthForCountryCode;
var countryCodeKnown = _lengths.TryGetValue(countryCode, out lengthForCountryCode);
var countryCodeKnown = Lengths.TryGetValue(countryCode, out lengthForCountryCode);
if (!countryCodeKnown)
{
return ValidationResult.CountryCodeNotKnown;
@ -29,14 +29,13 @@
value = value.ToUpper();
var newIban = value.Substring(4) + value.Substring(0, 4);
newIban = Regex.Replace(newIban, @"\D", match => ((int) match.Value[0] - 55).ToString());
newIban = Regex.Replace(newIban, @"\D", match => (match.Value[0] - 55).ToString());
var remainder = BigInteger.Parse(newIban) % 97;
if (remainder != 1)
return ValidationResult.ValueFailsModule97Check;
return ValidationResult.IsValid;
}
@ -50,7 +49,7 @@
CountryCodeNotKnown
}
private static Dictionary<string, int> _lengths = new Dictionary<string, int>
private static readonly IDictionary<string, int> Lengths = new Dictionary<string, int>
{
{"AL", 28},
{"AD", 24},

38
Task/IBAN/Forth/iban.fth Normal file
View file

@ -0,0 +1,38 @@
include lib/ulcase.4th \ for S>UPPER
include lib/triple.4th \ for UT/MOD
include lib/cstring.4th \ for C/STRING
include lib/todbl.4th \ for S>DOUBLE
0 constant ud>t \ convert unsigned double to triple
88529281 constant 97^4 \ first stage modulus
char A 10 - negate +constant c>u \ convert character to IBAN digit
: bank>t u>d rot 3 - 0 ?do 10 mu* loop 1000000000 ut* ;
\ convert country part to unsigned
: country>u ( a n -- u)
c/string c>u 10000 * >r c/string c>u 100 * >r number 100 mod abs r> + r> +
;
\ convert bank part to unsigned
: bank>u \ a n -- u)
c/string c>u 1000000 * >r \ get first digit and shift
c/string c>u 10000 * >r \ get second digit and shift
c/string c>u 100 * >r \ get third digit and shift
drop c@ c>u r> + r> + r> + \ combine all digits to number
;
: iban>t ( a n -- triple)
s>upper \ convert to upper case and get country
over 4 country>u >r 4 /string \ get bank part, save length, convert
over 4 bank>u >r 4 /string tuck s>double
1000000 mu* r> -rot r> u>d d+ 2>r \ now assemble everything except bank
bank>t 2r> ud>t t+ \ shift bank part and convert to triple
;
( a n -- f)
: iban? iban>t 97^4 ut/mod 2drop 97 mod 1 = ;
\ perform modulus 97 in two stages
: checkiban ( --)
." Enter your IBAN: " refill drop 0 parse -trailing iban?
if ." Valid" else ." Invalid" then cr
;
checkiban

View file

@ -0,0 +1,129 @@
:- object(iban).
:- info([
version is 0.1,
author is 'Paulo Moura',
date is 2015/10/11,
comment is 'IBAN validation example using DCG rules.'
]).
:- public(valid/1).
valid(IBAN) :-
phrase(iban, IBAN), !.
iban -->
country_code(Code), check_digits(Check), bban(BBAN),
{(BBAN*1000000 + Code*100 + Check) mod 97 =:= 1}.
country_code(Code) -->
letter_digits(L1, D3, D2), letter_digits(L0, D1, D0),
{country_code([L1, L0]), Code is D3*1000 + D2*100 + D1*10 + D0}.
check_digits(Check) -->
digit(D1), digit(D0),
{Check is D1*10 + D0}.
bban(BBAN) -->
bban_codes(Digits),
{digits_to_integer(Digits, BBAN, Count), Count =< 30}.
bban_codes(Ds) -->
" ", bban_codes(Ds).
bban_codes([D| Ds]) -->
digit(D), bban_codes(Ds).
bban_codes([D1, D0| Ds]) -->
letter_digits(_, D1, D0), bban_codes(Ds).
bban_codes([]) -->
[].
digit(D) -->
[C],
{0'0 =< C, C =< 0'9, D is C - 0'0}.
letter_digits(C, D1, D0) -->
[C],
{ ( 0'A =< C, C =< 0'Z ->
D is C - 0'A + 10
; 0'a =< C, C =< 0'z,
D is C - 0'a + 10
),
D1 is D div 10,
D0 is D mod 10
}.
digits_to_integer(Digits, BBAN, Count) :-
digits_to_integer(Digits, 0, BBAN, 0, Count).
digits_to_integer([], BBAN, BBAN, Count, Count).
digits_to_integer([Digit| Digits], BBAN0, BBAN, Count0, Count) :-
BBAN1 is BBAN0 * 10 + Digit,
Count1 is Count0 + 1,
digits_to_integer(Digits, BBAN1, BBAN, Count1, Count).
country_code("AL").
country_code("AD").
country_code("AT").
country_code("AZ").
country_code("BE").
country_code("BH").
country_code("BA").
country_code("BR").
country_code("BG").
country_code("CR").
country_code("HR").
country_code("CY").
country_code("CZ").
country_code("DK").
country_code("DO").
country_code("EE").
country_code("FO").
country_code("FI").
country_code("FR").
country_code("GE").
country_code("DE").
country_code("GI").
country_code("GR").
country_code("GL").
country_code("GT").
country_code("HU").
country_code("IS").
country_code("IE").
country_code("IL").
country_code("IT").
country_code("KZ").
country_code("KW").
country_code("LV").
country_code("LB").
country_code("LI").
country_code("LT").
country_code("LU").
country_code("MK").
country_code("MT").
country_code("MR").
country_code("MU").
country_code("MC").
country_code("MD").
country_code("ME").
country_code("NL").
country_code("NO").
country_code("PK").
country_code("PS").
country_code("PL").
country_code("PT").
country_code("RO").
country_code("SM").
country_code("SA").
country_code("RS").
country_code("SK").
country_code("SI").
country_code("ES").
country_code("SE").
country_code("CH").
country_code("TN").
country_code("TR").
country_code("AE").
country_code("GB").
country_code("VG").
:- end_object.

View file

@ -0,0 +1,2 @@
| ?- iban::valid("GB82 WEST 1234 5698 7654 32").
yes

View file

@ -0,0 +1,67 @@
(setq *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"))))
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Remove spaces and set upper case.
(define (sanitize-iban iban)
(upper-case (replace " " iban ""))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Check that only A-Z and 0-9 are used.
(define (valid-chars? iban)
(setq rx (string "[A-Z0-9]{" (length iban) "}" ))
(regex rx iban 1)
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Check that the length is correct for the country.
(define (valid-length? iban)
(setq countries-found (lookup (int (length iban)) *iban-code-length*))
(if (not (nil? countries-found))
(member (0 2 iban) countries-found)
)
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Convert the IBAN to integer following the rules from Wikipedia.
(define (iban-to-integer iban)
(setq country-code (0 2 iban))
(setq checksum (2 2 iban))
(setq iban (string (4 iban) country-code))
(setq iban (join (map (lambda (x) (if (regex "[0-9]" x) x (string (- (char x) 55)))) (explode iban))))
(bigint (string iban checksum))
)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Test if IBAN is correct (true) or not (nil):
;; (valid-iban? "GB82 WEST 1234 5698 7654 32") ==> true
;; (valid-iban? "GB82 TEST 1234 5698 7654 32") ==> nil
(define (valid-iban? iban)
(setq iban (sanitize-iban iban))
(and
(valid-chars? iban)
(valid-length? iban)
(= 1L (% (iban-to-integer iban) 97))
)
)

79
Task/IBAN/PHP/iban.php Normal file
View file

@ -0,0 +1,79 @@
<?php
function piece_wise($iban_all_digits) {
$remainder = NULL;
$slice = 9;
for ($i=0; $i<strlen($iban_all_digits); $i=$i+$slice)
{
if ($i>0)
{
$slice = 7;
}
$part = $remainder . substr($iban_all_digits, $i, $slice);
//echo "REMAINDER: " . $remainder . "<br>";
//echo "PART: $part" . "<br>";
$remainder = intval($part) % 97;
}
return $remainder;
}
$iban = "GB82 WEST 1234 5698 7654 32";
//remove space
$iban = str_replace(' ', '', $iban);
//echo $iban; echo '<br>';
$iban_length = strlen($iban);
$country_code = substr($iban, 0, 2);
/*
IBAN lengths are country specific
full list available at
https://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country
*/
$lengths = ['GB' => 22];
if ($lengths[$country_code] != $iban_length)
{
exit ("IBAN length not valid for $country_code");
}
// 2. move first four characters to the end
$iban = substr($iban, 4) . substr($iban, 0, 4);
//3. Replace letters in IBAN with digits
//(A=10, B=11 ... Z=35)
$iban_arr = str_split($iban, 1);
$iban_all_digits = '';
foreach ($iban_arr as $key=>$value)
{
if (ctype_alpha($value))
{
$value = ord($value) - 55;
}
$iban_all_digits = $iban_all_digits . $value;
}
if (piece_wise($iban_all_digits) === 1)
{
echo "VALID IBAN!";
}
else
{
echo "IBAN NOT VALID";
}

View file

@ -0,0 +1,92 @@
EnableExplicit
Enumeration IBAN
#IBAN_VAL
#IBAN_SUM
#IBAN_NOSPACE
#IBAN_VAL_FORM
#IBAN_SUM_FORM
EndEnumeration
NewMap CData.i()
Macro CCD(SIGN,LENGTH)
CData(SIGN)=LENGTH
EndMacro
Procedure.s IBANForm(iban.s,form.i)
Define fn.s, c.i
fn=RemoveString(UCase(iban),Chr(32))
If form=#IBAN_NOSPACE : ProcedureReturn fn : EndIf
fn=Mid(fn,5)+Mid(fn,1,4)
For c=65 To 90
fn=ReplaceString(fn,Chr(c),Str(c-55))
Next c
If form=#IBAN_VAL_FORM : ProcedureReturn fn : EndIf
fn=Left(fn,Len(fn)-2)+"00"
If form=#IBAN_SUM_FORM : ProcedureReturn fn : EndIf
EndProcedure
Procedure.s m97iban(iban.s,calculate.i)
Define i.i, part.s, rest.s
Select calculate
Case #IBAN_VAL : iban=IBANForm(iban,#IBAN_VAL_FORM)
Case #IBAN_SUM : iban=IBANForm(iban,#IBAN_SUM_FORM)
EndSelect
For i=1 To Len(iban) ; Validierung der Prüfsumme
part+Mid(iban,i,1)
If Val(rest+part)<97 : Continue : EndIf
rest=Str((Val(rest+part)) %97) : part=""
Next
Select calculate
Case #IBAN_VAL : ProcedureReturn rest
Case #IBAN_SUM : ProcedureReturn RSet(Str(98-Val(rest+part)),2,"0")
EndSelect
EndProcedure
CCD("AL",28) : CCD("AD",24) : CCD("AT",20) : CCD("AZ",28) : CCD("BE",16) : CCD("BH",22) : CCD("BA",20)
CCD("BR",29) : CCD("BG",22) : CCD("CR",21) : CCD("HR",21) : CCD("CY",28) : CCD("CZ",24) : CCD("DK",18)
CCD("DO",28) : CCD("EE",20) : CCD("FO",18) : CCD("FI",18) : CCD("FR",27) : CCD("GE",22) : CCD("DE",22)
CCD("GI",23) : CCD("GR",27) : CCD("GL",18) : CCD("GT",28) : CCD("HU",28) : CCD("IS",26) : CCD("IE",22)
CCD("IL",23) : CCD("IT",27) : CCD("KZ",20) : CCD("KW",30) : CCD("LV",21) : CCD("LB",28) : CCD("LI",21)
CCD("LT",20) : CCD("LU",20) : CCD("MK",19) : CCD("MT",31) : CCD("MR",27) : CCD("MU",30) : CCD("MC",27)
CCD("MD",24) : CCD("ME",22) : CCD("NL",18) : CCD("NO",15) : CCD("PK",24) : CCD("PS",29) : CCD("PL",28)
CCD("PT",25) : CCD("RO",24) : CCD("SM",27) : CCD("SA",24) : CCD("RS",22) : CCD("SK",24) : CCD("SI",19)
CCD("ES",24) : CCD("SE",24) : CCD("CH",21) : CCD("TN",24) : CCD("TR",26) : CCD("AE",23) : CCD("GB",22)
CCD("VG",24)
DataSection
IBANData:
Data.s "GB82 WEST 1234 5698 7654 32"
Data.s "GB82WEST12345698765432"
Data.s "gb82 west 1234 5698 7654 32"
Data.s "GB82 TEST 1234 5698 7654 32"
Data.s "GR16 0110 1250 0000 0001 2300 695"
Data.s "GB29 NWBK 6016 1331 9268 19"
Data.s "SA03 8000 0000 6080 1016 7519"
Data.s "CH93 0076 2011 6238 5295 7"
Data.s "IL62 0108 0000 0009 9999 999"
Data.s "IL62-0108-0000-0009-9999-999"
Data.s "US12 3456 7890 0987 6543 210"
Data.s "GR16 0110 1250 0000 0001 2300 695X"
Data.s Chr(0)
EndDataSection
Define iban.s, cc.s
OpenConsole()
Restore IBANData
Repeat
Read.s iban : If iban=Chr(0) : Break : EndIf
Print("IBAN"+#TAB$+": "+LSet(iban,35,Chr(32))+#TAB$)
cc=Left(IBANForm(iban,#IBAN_NOSPACE),2)
If CData(cc)
If Not CData()=Len(IBANForm(iban,#IBAN_NOSPACE)) : PrintN("[INCORRECT: LENGTH]") : Continue : EndIf
Else
PrintN("[INCORRECT: COUNTRY]") : Continue
EndIf
If Not Val(m97iban(iban,#IBAN_VAL))=1 : PrintN("[INCORRECT: MOD97]") : Continue : EndIf
If Not Right(IBANForm(iban,#IBAN_VAL_FORM),2)=m97iban(iban,#IBAN_SUM)
PrintN("[INCORRECT: CHECKSUM]") : Continue
EndIf
PrintN("[CORRECT]")
ForEver
Input()
End

View file

@ -1,4 +1,4 @@
/*REXX program validates an IBAN (International Bank Account Number). */
/*REXX program validates an IBAN (International Bank Account Number). */
@. =
@.1 = 'GB82 WEST 1234 5698 7654 32 '
@.2 = 'Gb82 West 1234 5698 7654 32 '
@ -11,37 +11,37 @@
@.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*/
parse arg @.0 /*get optional first argument from C.L.*/
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*/
if k==0 then leave /*User specified IBAN? Then we're 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.*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────VALIDATEIBAN subroutine───────────────────*/
validateIBAN: procedure; arg x; numeric digits 200 /*allow for big #s*/
x=space(x,0); L=length(x) /*elide blanks; determine the 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. */
'RS 22 SA 24 SE 24 SI 19 SK 24 SM 27 TN 24 TR 26 VG 24' /*country list.*/
@abc# = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' /*alphabet and decimal digits.*/
cc_=left(x,2); kk=substr(x,3,2) /*get IBAN country code and checkDigits*/
c#=wordpos(cc_,cc) /*find the country code index. */
cL=word(cc,c#+1) /*get the length of the country's IBAN.*/
e= '***error!*** invalid IBAN' /*literal used when displaying an error*/
if c#==0 then return e 'country code:' cc_
if \datatype(x,'A') then return e 'character:' substr(x,verify(x,@abc#),1)
if cL\==L then return e 'length:' L ' (should be' cL")"
y=substr(x,5)left(x,4) /*put four digs 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.'
if z//97==1 then return 0 /*check if correct remainder (modulus).*/
return e 'check digits.'

View file

@ -1,4 +1,4 @@
/*REXX program validates an IBAN (International Bank Account Number). */
/*REXX program validates an IBAN (International Bank Account Number). */
@. =
@.1 = 'GB82 WEST 1234 5698 7654 32 '
@.2 = 'Gb82 West 1234 5698 7654 32 '
@ -13,44 +13,44 @@
@.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*/
parse arg @.0 /*get optional first argument from C.L.*/
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*/
if k==0 then leave /*User specified IBAN? Then we're 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.*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────VALIDATEIBAN subroutine───────────────────────────────────────*/
validateIBAN: procedure; arg x; numeric digits 200 /*allow for big #s*/
x=space(x,0); L=length(x) /*elide blanks; determine the 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. */
'RS 22 SA 24 SE 24 SI 19 SK 24 SM 27 TN 24 TR 26 VG 24' /*country list.*/
@abc# = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' /*alphabet and decimal digits.*/
cc_=left(x,2); kk=substr(x,3,2) /*get IBAN country code and checkDigits*/
c#=wordpos(cc_,cc) /*find the country code index. */
cL=word(cc,c#+1) /*get the length of the country's IBAN.*/
e= '***error!*** invalid IBAN' /*literal used when displaying an error*/
if c#==0 then return e 'country code:' cc_
if \datatype(x,'A') then return e 'character:' substr(x,verify(x,@abc#),1)
if cL\==L then return e 'length:' L ' (should be' cL")"
if cc_=='BR' & date("S")<20130701 then return e "country, Brazil isn't valid until 1-July-2013."
if cc_=='GT' & date("S")<20140701 then return e "country, Guatemala isn't valid until 1-July-2014."
if cc_=='BA' & kk\==39 then return e "check digits for Bosnia and Herzegovina:" kk
if cc_=='MK' & kk\==07 then return e "check digits for Macedonia:" kk
if cc_=='ME' & kk\==25 then return e "check digits for Montenegro:" kk
if cc_=='PT' & kk\==50 then return e "check digits for Portugal:" kk
if cc_=='SI' & kk\==56 then return e "check digits for Slovenia:" kk
y=substr(x,5)left(x,4) /*put four digs 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.'
if z//97==1 then return 0 /*check if correct remainder (modulus).*/
return e 'check digits.'

View file

@ -0,0 +1,58 @@
Function validate_iban(s)
validate_iban = Chr(34) & s & Chr(34) & " is NOT valid."
Set cn_len = CreateObject("Scripting.Dictionary")
With cn_len
.Add "AL",28 : .Add "AD",24 : .Add "AT",20 : .Add "AZ",28 : .Add "BH",22 : .Add "BE",16
.Add "BA",20 : .Add "BR",29 : .Add "BG",22 : .Add "CR",21 : .Add "HR",21 : .Add "CY",28
.Add "CZ",24 : .Add "DK",18 : .Add "DO",28 : .Add "EE",20 : .Add "FO",18 : .Add "FI",18
.Add "FR",27 : .Add "GE",22 : .Add "DE",22 : .Add "GI",23 : .Add "GR",27 : .Add "GL",18
.Add "GT",28 : .Add "HU",28 : .Add "IS",26 : .Add "IE",22 : .Add "IL",23 : .Add "IT",27
.Add "JO",30 : .Add "KZ",20 : .Add "KW",30 : .Add "LV",21 : .Add "LB",28 : .Add "LI",21
.Add "LT",20 : .Add "LU",20 : .Add "MK",19 : .Add "MT",31 : .Add "MR",27 : .Add "MU",30
.Add "MC",27 : .Add "MD",24 : .Add "ME",22 : .Add "NL",18 : .Add "NO",15 : .Add "PK",24
.Add "PS",29 : .Add "PL",28 : .Add "PT",25 : .Add "QA",29 : .Add "RO",24 : .Add "SM",27
.Add "SA",24 : .Add "RS",22 : .Add "SK",24 : .Add "SI",19 : .Add "ES",24 : .Add "SE",24
.Add "CH",21 : .Add "TN",24 : .Add "TR",26 : .Add "AE",23 : .Add "GB",22 : .Add "VG",24
End With
iban = Replace(s," ","")
If cn_len.Exists(Left(iban,2)) And Len(iban) = cn_len.Item(Left(iban,2)) Then
'move the first 4 characters to the end
iban = Mid(iban,5,Len(iban)-4) & Left(iban,4)
'convert letters to numbers A=10 to Z=35
D = ""
For i = 1 To Len(iban)
If Asc(Mid(iban,i,1)) >= 65 And Asc(Mid(iban,i,1)) <= 90 Then
D = D & CStr(Asc(Mid(iban,i,1)) - 55)
Else
D = D & Mid(iban,i,1)
End If
Next
'piece-wise modulo calculation
Do
If Len(D) > 9 Then
N = CLng(Left(D,9)) Mod 97
D = CStr(N) & Mid(D,10,Len(D)-9)
Else
N = CLng(Left(D,9)) Mod 97
Exit Do
End If
Loop
If N = 1 Then
validate_iban = Chr(34) & s & Chr(34) & " is valid."
End If
End If
End Function
'test several scenarios
WScript.StdOut.WriteLine validate_iban("GB82 WEST 1234 5698 7654 32")
WScript.StdOut.WriteLine validate_iban("GB82WEST12345698765432")
WScript.StdOut.WriteLine validate_iban("gb82 west 1234 5698 7654 32")
WScript.StdOut.WriteLine validate_iban("GB82 TEST 1234 5698 7654 32")
WScript.StdOut.WriteLine validate_iban("GR16 0110 1250 0000 0001 2300 695")
WScript.StdOut.WriteLine validate_iban("GB29 NWBK 6016 1331 9268 19")
WScript.StdOut.WriteLine validate_iban("SA03 8000 0000 6080 1016 7519")
WScript.StdOut.WriteLine validate_iban("CH93 0076 2011 6238 5295 7")
WScript.StdOut.WriteLine validate_iban("IL62 0108 0000 0009 9999 999")
WScript.StdOut.WriteLine validate_iban("IL62-0108-0000-0009-9999-999")
WScript.StdOut.WriteLine validate_iban("US12 3456 7890 0987 6543 210")
WScript.StdOut.WriteLine validate_iban("GR16 0110 1250 0000 0001 2300 695X")