67 lines
2.5 KiB
Common Lisp
67 lines
2.5 KiB
Common Lisp
(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))
|
|
)
|
|
)
|