A few days ago I saw on Twitter a request for code that would convert roman numerals to decimal. CFLib has a UDF for going from decimal to Roman, but not the other way. I did a bit of searching and while I found a bunch of code libraries, I didn't find one that explained the logic behind the translation. Finally I came across this page: Roman Numerals, which I thought explained the issue very nicely. The basic process to convert from Roman to decimal is:

  1. Read the numbers from left to right.

  2. Each number is added to the next...

  3. Except when the next number is larger than the current number. Then you take the pair and do a subtraction.

So with this logic in mind, I came up with the following UDF. It assumes valid Roman numerals for input. But it seems to work ok.

function romantodec(input) { var romans = {}; var result = 0; var pos = 1; var char = ""; var thisSum = ""; var nextchar = "";

romans["I"] = 1; romans["V"] = 5; romans["X"] = 10; romans["L"] = 50; romans["C"] = 100; romans["D"] = 500; romans["M"] = 1000;

while(pos lte len(input)) { char = mid(input, pos, 1); //are we NOT at the end? if(pos != len(input)) { //check my next character - if bigger, replace with a sub nextchar = mid(input, pos+1, 1); if(romans[char] < romans[nextchar]) { thisSum = romans[nextchar] - romans[char]; result += thisSum; pos+=2; } else { result += romans[char]; pos++; } } else { result += romans[char]; pos++; } }

return result; }

You can see how it follows the basic, 'left to right, add the numbers together' process, and how it notices when the current character has a higher number to the right of it. I wrote up a quick test script for it like so:

<cfset inputs = "XX,XI,IV,VIII,MC,DL,XL"> <cfloop index="input" list="#inputs#"> <cfoutput> #input#=#romantodec(input)#<br/> </cfoutput> </cfloop>

Which produced:

XX=20
XI=11
IV=4
VIII=8
MC=1100
DL=550
XL=40

You can download this UDF at CFLib now: romanToDecimal

p.s. Sorry for those still waiting for UDF approval at CFLib. It is a volunteer process (myself, Scott Pinkston, Todd Sharp) so be patient!