(defun numeral-value (numeral) (cond ((char-equal numeral #\M) 1000) ((char-equal numeral #\D) 500) ((char-equal numeral #\C) 100) ((char-equal numeral #\L) 50) ((char-equal numeral #\X) 10) ((char-equal numeral #\V) 5) ((char-equal numeral #\I) 1) (t 0))) (defun numeral= (a b) (= (numeral-value a) (numeral-value b))) (defun numeral< (a b) (< (numeral-value a) (numeral-value b))) (defun numeral> (a b) (> (numeral-value a) (numeral-value b))) (defun numeral<= (a b) (<= (numeral-value a) (numeral-value b))) (defun numeral>= (a b) (>= (numeral-value a) (numeral-value b))) (defun parse-roman-numeral (numeral &key (current-value 0) (subtract 0)) (cond ((= (length numeral) 0) ;; in this case the whole input string has been consumed (- current-value subtract)) ((= (length numeral) 1) ;; in this case the input string is only one character long, ;; so just return its value plus whatever value has been ;; accumulated so far (- (+ (numeral-value (char numeral 0)) current-value) subtract)) ((numeral>= (char numeral 0) (char numeral 1)) ;; in this case the first numeral in the input string is ;; either equal to or greater than the second and so is ;; assumed to be taken literally (parse-roman-numeral (subseq numeral 1) :current-value (- (+ current-value (numeral-value (char numeral 0))) subtract))) ((numeral< (char numeral 0) (char numeral 1)) ;; in this case the first numeral in the input string is less ;; than the second and so is assumed to be a subtracter (parse-roman-numeral (subseq numeral 1) :current-value current-value :subtract (+ subtract (numeral-value (char numeral 0)))))))