BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Algorithms and Data Structures
.NET 1.1+

Convert Roman Numerals into Numbers

In an earlier article we converted integer values into Roman numerals, an ancient numbering system that uses letters to represent values. In this article we will reverse the process, allowing Roman numerals to be evaluated as an integer.

Digit Conversion and Rule 3

The next section of the code begins the conversion of the Roman numeral into an integer value whilst incorporating rule 3. This rule describes how a smaller-valued numeral before a larger one subtracts its value from the larger digit. The rule also provides several validations.

Let's review the code to be added to the end of the method first, then describe each part in turn.

// Create an ArrayList containing the values
int ptr = 0;
ArrayList values = new ArrayList();
int maxDigit = 1000;
while (ptr < roman.Length)
{
    // Base value of digit
    char numeral = roman[ptr];
    int digit = (int)Enum.Parse(typeof(RomanDigit), numeral.ToString());

    // Rule 3
    if (digit > maxDigit)
        throw new ArgumentException("Rule 3");

    // Next digit
    int nextDigit = 0;
    if (ptr < roman.Length - 1)
    {
        char nextNumeral = roman[ptr + 1];
        nextDigit = (int)Enum.Parse(typeof(RomanDigit), nextNumeral.ToString());

        if (nextDigit > digit)
        {
            if ("IXC".IndexOf(numeral) == -1 || nextDigit > (digit * 10)
                || roman.Split(numeral).Length > 3)
                throw new ArgumentException("Rule 3");
            
            maxDigit = digit - 1;
            digit = nextDigit - digit;
            ptr++;
        }
    }

    values.Add(digit);

    // Next digit
    ptr++;
}

The first section creates a simple pointer that will be used to point to each character in turn whilst skipping the second letter pairs that use subtractive combination. It also declares an ArrayList. This collection will contain the value of every digit or subtractive digit pair from the Roman numeral. These values that will be totalled later. An ArrayList has been selected because the required length is initially unknown and because it can later be accessed like an array using its indexer. The ArrayList class is in the System.Collections namespace so add using System.Collections; to the start of the code. Finally, the maximum permitted value of a digit is declared. This will be checked for each digit as the Roman numeral is parsed and reduced as subtractions are processed to permit checking of part of rule 3.

Once the variables are declared, a while loop is started. The loop will continue until the pointer variable has been increased to the point where it is pointing to a character beyond the end of the Roman numeral string.

The next section converts the numeral at the pointer position into an integer value by matching the character against the enumeration declared earlier. This is then tested to ensure it does not exceed the maximum digit value. If a further digit exists in the Roman numeral, this is also converted to an integer. The two values are compared and if the value of the first digit is less than the second then subtractive combination applies.

The next if statement performs three validation checks. Firstly the value being subtracted must be I, X or C. The second test ensures that the value being subtracted is at least one tenth of the value of the second numeral. If these tests are passed, the string is checked to ensure that the subtracted numeral does not appear twice or more elsewhere. We use the Split method again for this.

If all tests are passed, the maximum digit value is adjusted to support rule 3, the subtraction is performed and the result held as the current digit's value. The pointer variable is also incremented to skip the second letter in the pair.

Following the if statement, the value of the single numeral or the subtractive pair is added to the ArrayList for later totalling. The pointer variable is then increased to move to the next available numeral before the closing brace of the while loop.

If you haven't added the above code, add it to the end of the method now.

Rule 5

Rule 5 states that each numeral, or pair of subtractive numerals, must be greater in value than the following one. As we now have all of the values in the ArrayList, we can simply iterate through the values to validate. Add the following code to implement rule 5.

// Rule 5
for (int i = 0; i < values.Count - 1;i++)
{
    if ((int)values[i] < (int)values[i + 1])
        throw new ArgumentException("Rule 5");
}

Rule 2

The last rule to be created is rule 2. This rule explains that the values of the numerals and subtractive pairs can be totalled to determine the final value of the Roman numeral. This is achieved with a final loop through the values collection. Add the following to the end of the method to complete the class.

// Rule 2
int total = 0;
foreach (int digit in values)
{
    total += digit;
}
return total;
22 January 2008