Roman Numeral Conversion in Both Directions
Convert integers from 1 to 3999 into Roman numerals and parse valid numerals back to numbers with subtraction and validation.
Code
const NUMERALS = [
[1000, "M"], [900, "CM"], [500, "D"], [400, "CD"],
[100, "C"], [90, "XC"], [50, "L"], [40, "XL"],
[10, "X"], [9, "IX"], [5, "V"], [4, "IV"], [1, "I"],
];
export function toRoman(value) {
if (!Number.isInteger(value) || value < 1 || value > 3999) {
throw new RangeError("value must be an integer between 1 and 3999");
}
let remaining = value;
let output = "";
for (const [amount, symbol] of NUMERALS) {
while (remaining >= amount) {
output += symbol;
remaining -= amount;
}
}
return output;
}
export function fromRoman(roman) {
if (typeof roman !== "string" || !/^[MDCLXVI]+$/.test(roman)) {
throw new RangeError("roman must contain only MDCLXVI");
}
const values = { M: 1000, D: 500, C: 100, L: 50, X: 10, V: 5, I: 1 };
let total = 0;
for (let index = 0; index < roman.length; index += 1) {
const current = values[roman[index]];
const next = values[roman[index + 1]] ?? 0;
total += current < next ? -current : current;
}
if (total < 1 || total > 3999 || toRoman(total) !== roman) {
throw new RangeError("invalid or non-canonical roman numeral");
}
return total;
}Report a problem with this exampleOpens a pre-filled issue on GitHub.