62 lines
2.6 KiB
Common Lisp
62 lines
2.6 KiB
Common Lisp
;;
|
|
;; 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
|
|
always (valid-alphanum char))))
|
|
|
|
;;
|
|
;; 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))))
|