Skip to content

Instantly share code, notes, and snippets.

@brymck
Created May 19, 2014 00:03
Show Gist options
  • Save brymck/9d2f1c00661e17aa4d2c to your computer and use it in GitHub Desktop.
Save brymck/9d2f1c00661e17aa4d2c to your computer and use it in GitHub Desktop.
Appends the check digit to a CUSIP
;; Example usage:
;; (cusip "ABCD1234")
;; => "ABCD12348"
(use '[clojure.string :as string])
(defn clean-cusip
"Converts a string into an unchecked 8-character CUSIP, padding with '0' if
necessary"
[s]
(let [s (string/upper-case s)
len (count s)]
(if (< len 8)
(str s (apply str (repeat (- 8 len) \0)))
(subs s 0 8))))
(defn cusip-value
"Returns the number value of a valid CUSIP character (A-Z, 0-9, *, @, #)"
[c]
(let [i (int c)]
(cond (and (>= i 48) (<= i 57)) (- i 48)
(and (>= i 65) (<= i 90)) (- i 55)
(= c \*) 36
(= c \@) 37
(= c \#) 38
:else (throw (Exception. (format "'%s' is not a valid character" c))))))
(defn ones-digit
"Retrieves the ones digit of an integer"
[^long x]
(rem x 10))
(defn sum-cusip-values
"Sums the values of the CUSIP"
[s]
(loop [[c & rst] s
sum 0
i 0]
(let [v (cusip-value c)
v (if (odd? i) (* v 2) v)
sum (+ sum (quot v 10) (ones-digit v))]
(if (empty? rst)
sum
(recur rst sum (inc i))))))
(defn cusip
"Returns a 9-character CUSIP, including its check digit"
[s]
(let [s (clean-cusip s)]
(->> s
sum-cusip-values
ones-digit
(- 10)
ones-digit
(str s))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment