← Runnable Projects

阅读中文版本

Roman Numeral Converter CLI

A Node CLI that converts integers to Roman numerals and back, rejecting out-of-range and malformed input with clear errors and tests.

beginnerjavascriptunverified

Project

node-roman-numeral-cli

Entry point: roman.mjs

Install

node --version

Run

node roman.mjs 1994

Test

node --test roman.test.mjs

Expected output

Prints the Roman numeral for the given integer, for example MCMXCIV for 1994. Passing -r converts in reverse.

Dependencies

  • node >=20

What it does

Greedily maps an integer onto the standard subtractive notation and validates the 1 to 3999 range. With -r it parses a numeral and rejects malformed strings by checking each token.

const MAP = [
  [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(n) {
  if (!Number.isInteger(n) || n < 1 || n > 3999) throw new RangeError('out of range 1..3999');
  let out = '';
  for (const [value, sym] of MAP) while (n >= value) { out += sym; n -= value; }
  return out;
}

export function fromRoman(s) {
  if (!/^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/.test(s)) throw new SyntaxError('invalid numeral');
  let total = 0;
  for (let i = 0; i < s.length; i++) {
    const cur = MAP.find(([, sym]) => sym.length === 1 && sym === s[i])?.[0] ?? 0;
    const nxt = i + 1 < s.length ? (MAP.find(([, sym]) => sym.length === 1 && sym === s[i + 1])?.[0] ?? 0) : 0;
    total += cur < nxt ? -cur : cur;
  }
  return total;
}

const args = process.argv.slice(2);
if (args[0] === '-r') console.log(fromRoman(args[1]));
else console.log(toRoman(Number(args[0])));

Run and verify

node roman.mjs 1994

Run the test command to check the implementation: node --test roman.test.mjs.

Expected Output

1994 in standard form is MCMXCIV (1000 + 900 + 90 + 4). The default direction converts an integer to a numeral:

MCMXCIV

Limitations

Supports the standard 1 to 3999 range only, because classical notation has no zero or negative form and no dedicated symbols above 3999.