BTW, cl-format (my Common Lisp format function for Clojure), supports the ~...@r directive for converting Arabic to Roman (but nothing to go the other way around. I didn't spend too much time thinking about stylistic issues when I wrote it, but if you're interested you can compare. It's at http://github.com/tomfaulhaber/cl-format.)
On Mar 3, 3:40 am, David Sletten <da...@bosatsu.net> wrote: > Here's a little toy to practice my basic Clojure skills. I didn't see > any similar topic in the archives, so here we go... > > This code performs conversions between Roman and Arabic numerals. > Roman numerals are represented as strings and Arabic numerals are > just integers. Arabic numerals in the range of 1 and 3999 inclusive > are allowed. Conventionally, 3999 is the upper limit since the Roman > numeral for 5000 (a V with a bar over it) cannot be represented in > ASCII (although it exists in Unicode). > > The function roman-to-arabic-aux correctly converts any valid Roman > numeral. This can be exhaustively tested by comparing the Roman > numeral output of Common Lisp's FORMAT function for example (e.g., > (format nil "~...@r" n)). The trick, however, is weeding out bogus > strings representing invalid Roman numerals such as IVI, IXV, etc... > For this purpose the function "roman?" uses a regular expression I > cribbed from Perl's CPAN module Roman.pm (http://search.cpan.org/ > ~chorny/Roman-1.23/lib/Roman.pm). > > arabic-to-roman performs the obvious conversion in the other direction. > > Incidentally, the "cond" form in roman-to-arabic-aux seems to me > harder to read in Clojure than it would be in CL with its additional > set of grouping parentheses. When you can't fit both the predicate > and the consequent expression on the same line it gets confusing. > > I'd appreciate any feedback regarding my Clojure style. Any more > natural ways to do things? > > Aloha, > David Sletten > > (def roman-values-map {\I 1 \V 5 \X 10 \L 50 \C 100 \D 500 \M 1000}) > > (defn value [roman] > (get roman-values-map (Character/toUpperCase roman))) > > (defn roman? [roman-string] > (and (not (empty? roman-string)) > (re-matches > #"(?:M{0,3})(?:D?C{0,3}|C[DM])(?:L?X{0,3}|X[LC])(?:V?I{0,3}|I > [VX])$" > roman-string))) > > (defn roman-to-arabic-aux [roman-string] > (cond (empty? roman-string) 0 > (empty? (rest roman-string)) (value (first roman-string)) > (< (value (first roman-string)) (value (second roman-string))) > (- (roman-to-arabic-aux (rest roman-string)) > (value (first roman-string))) > :else > (+ (value (first roman-string)) > (roman-to-arabic-aux (rest roman-string))))) > > (defn roman-to-arabic [roman-string] > (if (roman? roman-string) > (roman-to-arabic-aux roman-string) > (format "'%s' is not a valid Roman numeral." roman-string))) > > (def arabic-values '((1000 "M") (900 "CM") (500 "D") (400 "CD") > (100 "C") (90 "XC") (50 "L") (40 "XL") > (10 "X") (9 "IX") (5 "V") (4 "IV") (1 "I"))) > > (defn arabic-to-roman > ([n] (if (<= 1 n 3999) > (apply str (arabic-to-roman n arabic-values)) > (format "%d cannot be converted." n))) > ([n num-list] (cond (empty? num-list) '() > (zero? n) '() > :else (let [[[arabic roman] & tail] num-list] > (if (>= n arabic) > (cons roman (arabic-to-roman (- n > arabic) > num-list)) > (arabic-to-roman n tail)))) )) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---