JavaScript Roman Numeral Converter

This simple tool, written in JavaScript, will convert Roman numerals to an integer and integers to Roman numerals.

In order to handle very large numbers, the tool uses the conversion chart below and is therefore case-sensitive. The lowercase numerals are traditionally represented capitalized and overlined.

Conversion Chart

I: 1
V: 5           v: 5,000
X: 10          x: 10,000
L: 50          l: 50,000
C: 100         c: 100,000
D: 500         d: 500,000
M: 1,000       m: 1,000,000

The Code Download

var romanToInt = function (numeral) {
    "use strict";
    var romanNumerals = {
        "I": 1,
        "V": 5,
        "X": 10,
        "L": 50,
        "C": 100,
        "D": 500,
        "M": 1000,
        "v": 5000,
        "x": 10000,
        "l": 50000,
        "c": 100000,
        "d": 500000,
        "m": 1000000
    };

    /**
     * Takes a string and returns true if each character is
     * a valid roman numeral
     * @param {String} val
     * @returns {Boolean}
     */
    function isValidNumeral(val) {
        var i = 0;
        for (i; i < val.length; i += 1) {
            if (romanNumerals[val.charAt(i)] === undefined) {
                return false;
            }
        }
        return true;
    }

    /**
     * Takes a string containing only valid roman numerals
     * and returns its arabic numeral equivalent
     * @param {String} val
     * @returns {Number}
     */
    function calculateIntValue(val) {
        var result = 0,
            c = 0,
            cm = 0,
            i = (val.length - 1);
        for (i; i >= 0; i -= 1) {
            c = parseInt(romanNumerals[val.charAt(i)], 10);
            cm = parseInt(romanNumerals[val.charAt(i - 1)], 10);
            if (isNaN(cm) || cm >= c) {
                result += c;
            } else {
                result += c - cm;
                i -= 1;
            }
        }
        return result;
    }

    /**
     * Takes an integer and returns its roman numeral equivalent.
     * @param {Number} v
     * @returns {String}
     */
    function calculateRomanVal(v) {
        var str = '',
            numeralKeys = Object.keys(romanNumerals),
            maxVal = numeralKeys[numeralKeys.length - 1], // largest Roman Numeral
            cr = maxVal,
            fstr,
            r;
        while (v > 0) {
            for (r in romanNumerals) {
                if (romanNumerals.hasOwnProperty(r)) {
                    if (romanNumerals[r] > v || r === maxVal) {
                        if (r === maxVal && v > romanNumerals[r]) {
                            // The number is larger than the largest Roman numeral
                            v = v - romanNumerals[r];
                            str = (str + r);
                        } else {
                            // The number is smaller than the current numeral
                            v = v - romanNumerals[cr];
                            str = (str + cr);
                            // Replace any four-ofs with the proper 2-character combo
                            // (i.e. IIII becomes IV)
                            fstr = new Array(5).join(cr);
                            str = str.replace(fstr, (cr + numeralKeys[numeralKeys.indexOf(cr) + 1]));
                        }
                        break;
                    }
                    cr = r;
                }
            }
        }
        return str;
    }

    (function main() {
        var toHTML = 'result', //id of element to write result to
            val = numeral,
            result = '',
            noNumberErrorMsg = 'Enter a valid Roman Numeral or integer above',
            invalidNumberErrorMsg = 'Invalid Roman Numeral or integer';
        if (val.length === 0) {
            result = noNumberErrorMsg;
        } else if (isValidNumeral(val)) {
            result = val + ' Expressed in Arabic Numerals: ' + calculateIntValue(val);
        } else if (parseInt(val, 10) == val) { // soft equals to compare int val with string
            result = val + ' Expressed in Roman Numerals: ' + calculateRomanVal(val);
        } else {
            result = invalidNumberErrorMsg;
        }
        document.getElementById(toHTML).innerHTML = result;
    }());
};

© 2006-2018 quixfox at gmail dot com - some rights reserved - top