Converting to and from Roman Numerals

This blog deals with conversions between Roman numerals and decimal integers.

The question of how to convert the Roman numerals to decimal integers recently came up on the forums.
As, the C# implementations I could find on the internet were either over-complicated or defective in some way, I thought I'd write my own.
 
I've also written a method to convert in the opposite direction; from decimal integers to the Roman numerals, and the code has been reproduced below in case it's of help to anyone.
 
Please note that the only Roman numerals, as commonly used today, are dealt with i.e. the symbol set is: I, V, X, L, C, D and M.
I've also followed the convention, that, not more than three symbols of the same kind can be used together. So 'IIII' (for 4) is regarded as invalid and you should use 'IV' instead, which is an example of the, so called, 'subtractive notation'.
 
It follows from this that only the decimal integers in the range 1 to 3999 can be validly represented as Roman numerals and an attempt to convert the numbers outside this range therefore results in an exception.
 
  1. using System;  
  2. using System.Text;  
  3.   
  4. namespace RomanNumerals  
  5. {  
  6.     static class Roman  
  7.     {  
  8.         static string[] roman1 = { "MMM""MM""M" };  
  9.         static string[] roman2 = { "CM""DCCC""DCC""DC""D""CD""CCC""CC""C" };  
  10.         static string[] roman3 = { "XC""LXXX""LXX""LX""L""XL""XXX""XX""X" };  
  11.         static string[] roman4 = { "IX""VIII""VII""VI""V""IV""III""II""I" };  
  12.   
  13.         public static bool TryParse(string text, out int value)  
  14.         {  
  15.             value = 0;  
  16.             if (String.IsNullOrEmpty(text)) return false;  
  17.             text = text.ToUpper();  
  18.             int len = 0;  
  19.   
  20.             for (int i = 0; i < 3; i++)  
  21.             {  
  22.                 if (text.StartsWith(roman1[i]))  
  23.                 {  
  24.                     value += 1000 * (3 - i);  
  25.                     len = roman1[i].Length;  
  26.                     break;  
  27.                 }  
  28.             }  
  29.   
  30.             if (len > 0)  
  31.             {  
  32.                 text = text.Substring(len);  
  33.                 len = 0;  
  34.             }  
  35.   
  36.             for (int i = 0; i < 9; i++)  
  37.             {  
  38.                 if (text.StartsWith(roman2[i]))  
  39.                 {  
  40.                     value += 100 * (9 - i);  
  41.                     len = roman2[i].Length;  
  42.                     break;  
  43.                 }  
  44.             }  
  45.   
  46.             if (len > 0)  
  47.             {  
  48.                 text = text.Substring(len);  
  49.                 len = 0;  
  50.             }  
  51.   
  52.             for (int i = 0; i < 9; i++)  
  53.             {  
  54.                 if (text.StartsWith(roman3[i]))  
  55.                 {  
  56.                     value += 10 * (9 - i);  
  57.                     len = roman3[i].Length;  
  58.                     break;  
  59.                 }  
  60.             }  
  61.   
  62.             if (len > 0)  
  63.             {  
  64.                 text = text.Substring(len);  
  65.                 len = 0;  
  66.             }  
  67.   
  68.             for (int i = 0; i < 9; i++)  
  69.             {  
  70.                 if (text.StartsWith(roman4[i]))  
  71.                 {  
  72.                     value += 9 - i;  
  73.                     len = roman4[i].Length;  
  74.                     break;  
  75.                 }  
  76.             }  
  77.   
  78.             if (text.Length > len)  
  79.             {  
  80.                 value = 0;  
  81.                 return false;  
  82.             }  
  83.   
  84.             return true;  
  85.         }  
  86.   
  87.         public static string ToRoman(int num)  
  88.         {  
  89.             if (num > 3999) throw new ArgumentException("Too big - can't exceed 3999");  
  90.             if (num < 1) throw new ArgumentException("Too small - can't be less than 1");  
  91.             int thousands, hundreds, tens, units;  
  92.             thousands = num / 1000;  
  93.             num %= 1000;  
  94.             hundreds = num / 100;  
  95.             num %= 100;  
  96.             tens = num / 10;  
  97.             units = num % 10;  
  98.             var sb = new StringBuilder();  
  99.             if (thousands > 0) sb.Append(roman1[3 - thousands]);  
  100.             if (hundreds > 0) sb.Append(roman2[9 - hundreds]);  
  101.             if (tens > 0) sb.Append(roman3[9 - tens]);  
  102.             if (units > 0) sb.Append(roman4[9 - units]);  
  103.             return sb.ToString();  
  104.         }  
  105.     }   
  106.   
  107.     class Program  
  108.     {  
  109.         static void Main()  
  110.         {  
  111.             string[] romans = { "I""MMIV""DCL""CCXXII""IIII""CZ""MLXVI""III""DCCXIV""MIM" };  
  112.             int value = 0;  
  113.   
  114.             foreach (string roman in romans)  
  115.             {  
  116.                 if (Roman.TryParse(roman, out value)) Console.WriteLine("{0} = {1}", roman, value);  
  117.             }  
  118.   
  119.             Console.WriteLine();  
  120.   
  121.             int[] numbers = { 1, 2004, 650, 222, 4, 99, 1066, 3, 714, 1999, 3999 };  
  122.   
  123.   
  124.             foreach (int number in numbers)  
  125.             {  
  126.                 Console.WriteLine("{0} = {1}", number, Roman.ToRoman(number));  
  127.             }  
  128.   
  129.             Console.ReadKey();  
  130.         }  
  131.           
  132.     }  
  133. }  
The output of this program is:
 
I = 1
MMIV = 2004
DCL = 650
CCXXII = 222
MLXVI = 1066
III = 3
DCCXIV = 714
 
1 = I
2004 = MMIV
650 = DCL
222 = CCXXII
4 = IV
99 = XCIX
1066 = MLXVI
3 = III
714 = DCCXIV
1999 = MCMXCIX
3999 = MMMCMXCIX
 
For further details on Roman numerals, check out this Wikipedia article: