Convert roman numerals to numbers in R
Asked Answered
T

3

32

In R, there is a great function as.roman in the very base setup:

as.roman(79)
# [1] LXXIX

Is there an inverse function that would convert roman numerals to numbers?

(I know I can write it myself but I prefer to use already prepared or preferably standard functions, unfortunatelly cannot find one. Standard library or package function is a prefered solution)

Torrey answered 14/1, 2014 at 15:3 Comment(0)
W
44

as.roman() returns an object of class roman, so R recognizes it as such. You can directly turn it back into an Arabic numeral with as.numeric(). If you have a string that meets the criteria such that it could be a valid roman numeral, you can coerce it to a class roman object with as.roman(), and then coerce it into an Arabic numeral by composing the coercion functions. Consider:

> as.roman(79)
[1] LXXIX
> x <- as.roman(79)
> x
[1] LXXIX
> str(x)
Class 'roman'  int 79
> as.roman("LXXIX")
[1] LXXIX
> as.numeric(as.roman("LXXIX"))
[1] 79
Whereon answered 14/1, 2014 at 15:7 Comment(0)
A
12

From as.roman code you can find .roman2numeric and its code can be seen if you run getAnywhere(".roman2numeric")

The code is:

function (x) 
{
  romans <- c("M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", 
              "IX", "V", "IV", "I")
  numbers <- c(1000L, 900L, 500L, 400L, 100L, 90L, 50L, 40L, 
               10L, 9L, 5L, 4L, 1L)
  out <- integer(length(x))
  ind <- is.na(x)
  out[ind] <- NA
  if (any(!ind)) {
    y <- toupper(x[!ind])
    y <- gsub("CM", "DCCCC", y)
    y <- gsub("CD", "CCCC", y)
    y <- gsub("XC", "LXXXX", y)
    y <- gsub("XL", "XXXX", y)
    y <- gsub("IX", "VIIII", y)
    y <- gsub("IV", "IIII", y)
    ok <- grepl("^M{,3}D?C{,4}L?X{,4}V?I{,4}$", y)
    if (any(!ok)) {
      warning(sprintf(ngettext(sum(!ok), "invalid roman numeral: %s", 
                               "invalid roman numerals: %s"), paste(x[!ind][!ok], 
                                                                    collapse = " ")), domain = NA)
      out[!ind][!ok] <- NA
    }
    if (any(ok)) 
      out[!ind][ok] <- sapply(strsplit(y[ok], ""), function(z) as.integer(sum(numbers[match(z, 
                                                                                            romans)])))
  }
  out
}

You can access to .roman2numeric and convert roman number to decimal numbers the way @rawr suggested in his/her comment.

> utils:::.roman2numeric("III")
[1] 3
> utils:::.roman2numeric("XII")
[1] 12
> utils:::.roman2numeric("LXXIX")
[1] 79
Allenaallenby answered 14/1, 2014 at 15:12 Comment(0)
A
8

The roman numbers in R are, according to the docs:

objects of class "roman" which are internally represented as integers, and have suitable methods for printing, formatting, subsetting, and coercion to character.

You should therefore be able to get the integer value back using as.integer():

as.integer(as.roman(79)+as.roman(12))
Acquah answered 14/1, 2014 at 15:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.