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:
-
Read the numbers from left to right.
-
Each number is added to the next...
-
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.
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;
}
function romantodec(input) {
var romans = {};
var result = 0;
var pos = 1;
var char = "";
var thisSum = "";
var nextchar = "";
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!