In Emacs Lisp, how to write an Emacs Lisp function to convert a natural number from roman numerals representation to the equivalent Emacs Lisp integer value? The Emacs Lisp function should be callable from Emacs Lisp and return an Emacs Lisp integer object for further processing in an Emacs Lisp program. I would like to accomplish this with Emacs Lisp, so I'm not expecting answers written as keyboard macros, other Lisp dialects, or shell scripts. Answers written as one or more Emacs Lisp functions would be ideal, thanks!
Background:
I gather data from all kinds of sources, and occasionally people use numbers written as roman numerals. Such numbers are not very useful for sorting and comparing with numbers in other forms. I decided it should be doable in Lisp, but if Emacs contains any function to do the conversion, I could not find it. (Maybe it is in an external library?)
Here's the most applicable solution I found via a general web search:
https://www.rosettacode.org/wiki/Roman_numerals/Decode#Emacs_Lisp
Unfortunately this function expects the number to be encoded as one Emacs Lisp symbol per digit, or a list of such symbol encoded digits. When dealing with web data, file names, or most other sources the roman numerals will most likely be in an Emacs Lisp string object.
My solution: Write a wrapper function to convert a string into symbol or list of symbols as required for the funciton linked above. (Is this really the best way?)
(defun ro2ar (RN)
"translate a roman number RN into arabic number.
Its argument RN is wether a symbol, wether a list.
Returns the arabic number. (ro2ar 'C) gives 100,
(ro2ar '(X X I V)) gives 24"
(cond
((eq RN 'M) 1000)
((eq RN 'D) 500)
((eq RN 'C) 100)
((eq RN 'L) 50)
((eq RN 'X) 10)
((eq RN 'V) 5)
((eq RN 'I) 1)
((null (cdr RN)) (ro2ar (car RN))) ;; stop recursion
((< (ro2ar (car RN)) (ro2ar (car (cdr RN)))) (- (ro2ar (cdr RN)) (ro2ar (car RN)))) ;; "IV" -> 5-1=4
(t (+ (ro2ar (car RN)) (ro2ar (cdr RN)))))) ;; "VI" -> 5+1=6
=> ro2ar
(defun roman-numerals-to-integer (rn)
"Return the integer value of the natural number represented by RN.
RN may be a string, single digit symbol, or list of single digit
symbols.
URL `https://www.rosettacode.org/wiki/Roman_numerals/Decode#Emacs_Lisp'"
(ro2ar
(if (not (stringp rn))
rn
(mapcar
(lambda (x)
(intern (string x)))
rn))))
=> roman-numerals-to-integer
(mapcar 'roman-numerals-to-integer
'(M D C L X V I))
=> (1000 500 100 50 10 5 1)
(roman-numerals-to-integer '(M D C L X V I))
=> 1666
(roman-numerals-to-integer "MDCLXVI")
=> 1666