You are here

Convert Roman numerals to decimal integers in C++

// Converts Roman numerals to decimal integers.
// This code is very resilient to non-standard or variant forms, but does not handle
// exotic forms such as fractions (S etc.), the overstrike x1000 operator or unicode numerals.
// Andrew Fountain, released under GPL 3.0 or higher
#define ID "$Id: roman_num.cpp 46 2012-08-03 18:24:25Z andrewfn $"
#include <iostream>
#include <string.h>
using namespace std;

/* Helper function for romChars()
 * return the value of a Roman character, or zero if not a valid character
 */
int romCharVal(char ch) {// C    D  E F G H  I  J K   L     M  N O P Q R S T U  V  W   X
  static int romval[] = { 100, 500, 0,0,0,0, 1, 0,0, 50, 1000, 0,0,0,0,0,0,0,0, 5, 0, 10 };
  int i = ch - 'C';
  if ((i >= 0) && (i <= ('X'-'C'))) return romval[i];
  else return 0;
}

/* Takes a pair of Roman numerals and modifies *dec by the value of the first one
 * comparing it to the second to see if it is to be added or subtracted.
 * A value of FALSE is returned if ch is a character that is not a valid Roman numeral.
 * An invalid alphanumeric character will cause the dec to be set to zero.
 * Note that this will successfully convert even variant forms, e.g. IIII (4) or IM (999).
 */
bool romChars(int * dec, char ch, char ch2) {
  if (!isalnum(ch)) return false; // Roman numeral has been terminated
  int romval = romCharVal(ch);
  if (romval == 0) { // illegal character, so return zero value
    *dec = 0;
    return false;
  }
  if (romval >= romCharVal(ch2)) *dec += romval; // if character larger than the next one: add
  else *dec -= romval; // if character less than the following one, then subtract
  return true;
}

/* Example conversion function: returns the integer value of a Roman numeral character string.
 * The string is terminated by a space or non-alphanumeric characters
 * If there are any invalid alphanumeric characters, the function returns 0
 */
int rom2int(const char * roman) {
  int dec = 0;
  for (const char *r = roman; *r; r++) {
    if (!romChars(&dec, *r, *(r+1))) break;
  }
  return dec;
}

/* test code */
int main (int argc, char *argv[]) {
  const char *roman[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", //1-15
    "XXXVIII", "XXXIX", "XL", "XLI", "XLII", "XLIII", "XLIV", "XLV", //38-45
     "MCMLXXXVIII", "MCMLXXXIX", "MCMXC", "MCMXCI", "MCMXCII", "MCMXCIII", "MCMXCIV", //1988-1994
     "MCMXCV", "MCMXCVI", "MCMXCVII", "MCMXCVIII", "MCMXCIX", "MM ",  //1995-2000
     "IIII", "VIIII.", "IC", "MIM", "XJ", "KII", "I1", ""}; // Non-standard 4, 9, 99, 1999, + 3 errors
  for (size_t i=0; strlen(roman[i]); i++) {
    cout << rom2int(roman[i]) << " = " << roman[i] << endl;
  }
}
Topic: