47 lines
1.5 KiB
Clojure
47 lines
1.5 KiB
Clojure
(defn- char->value
|
|
"convert the given char c to a value used to calculate the cusip check sum"
|
|
[c]
|
|
(let [int-char (int c)]
|
|
(cond
|
|
(and (>= int-char (int \0)) (<= int-char (int \9))) (- int-char 48)
|
|
(and (>= int-char (int \A)) (<= int-char (int \Z))) (- int-char 55)
|
|
(= c \*) 36
|
|
(= c \@) 37
|
|
(= c \#) 38
|
|
:else nil)))
|
|
|
|
(defn- calc-sum
|
|
"Calculate cusip sum. nil is returned for an invalid cusip."
|
|
[cusip]
|
|
(reduce
|
|
(fn [sum [i c]]
|
|
(if-let [v (char->value c)]
|
|
(let [v (if (= (mod i 2) 1) (* v 2) v)]
|
|
(+ sum (int (+ (/ v 10) (mod v 10)))))
|
|
(reduced nil)))
|
|
0
|
|
(map-indexed vector (subs cusip 0 8))))
|
|
|
|
(defn calc-cusip-checksum
|
|
"Given a valid 8 or 9 digit cusip, return the 9th checksum digit"
|
|
[cusip]
|
|
(when (>= (count cusip) 8)
|
|
(let [sum (calc-sum cusip)]
|
|
(when sum
|
|
(mod (- 10 (mod sum 10)) 10)))))
|
|
|
|
(defn is-valid-cusip9?
|
|
"predicate validating a 9 digit cusip."
|
|
[cusip9]
|
|
(when-let [checksum (and (= (count cusip9) 9)
|
|
(calc-cusip-checksum cusip9))]
|
|
(= (- (int (nth cusip9 8)) 48)
|
|
checksum)))
|
|
|
|
(defn rosetta-output
|
|
"show some nice output for the Rosetta Wiki"
|
|
[]
|
|
(doseq [cusip ["037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105" "EXTRACRD8"
|
|
"EXTRACRD9" "BADCUSIP!" "683&9X106" "68389x105" "683$9X106" "68389}105" "87264ABE4"]]
|
|
(println cusip (if (is-valid-cusip9? cusip) "valid" "invalid"))))
|