Location: PHPKode > scripts > Dec 2 Roman Converter > dec-2-roman-converter/Dec2RomanNumConverter.class.php
<?php
/**
  * Class for converting decimal to Roman numbers.
  *
  * @package Dec2RomanNumConverter
  * @author Nikola Posa, www.nikolaposa.in.rs
  * @license GNU General Public License (GPL)
  */
class Dec2RomanNumConverter
{
	/**
	  * Common Roman numerals array, with appropriate decimal
	  * numbers as indexes.
	  *
	  * @access private
	  */
	private $basic_numbers = array
	(
		1 	  => 'I',
		2 	  => 'II',
		3 	  => 'III',
		4 	  => 'IV',
		5 	  => 'V',
		6 	  => 'VI',
		7 	  => 'VII',
		8 	  => 'VIII',
		9 	  => 'IX',
		10 	  => 'X',
		50 	  => 'L',
		100   => 'C',
		500   => 'D',
		1000  => 'M',	
		5000  => '<span style = "border-top: 1px solid;">V </span>',
		10000 => '<span style = "border-top: 1px solid;">X </span>'
	);
	
	/**
	  * Function for converting decimal numbers to Roman.
	  *
	  * @param int Decimal number.
	  * @return string Roman numeral.
	  * @access public
	  */
	public function dec2roman($dn)
	{			
		if ($dn > 10999) { //Cheks if argument is larger than 10999 because this algorithm can't process such large numbers (yet ;)).
			throw new Exception('Are you kidding me?');
		}
		
		if (array_key_exists($dn, $this->basic_numbers)) { //If the argument is in common numbers array, there's no need to run whole algorithm.
			return $this->basic_numbers[$dn];
		}
		
		//Here we go...
		$roman_num = '';
		
		$dec_num = $dn;
		if (!is_string($dec_num)) { //Converting argument to string, if it isn't that type.
			$dec_num = strval($dec_num);
		}
		
		$dec_num_length = strlen($dec_num); //Getting number of numerals.
		
		for ($i = 0; $i < $dec_num_length; $i++) { //Looping through all numerals.
			if ($i == $dec_num_length - 1) { //If we've reached the last number, we just need to replace that number with proper number from the $basic_numbers array.
				$roman_num .= $this->basic_numbers[$dec_num{$i}];
			}
			else {		 
				//Getting the base of the position of the current numeral (1, 10, 100, 1000...).
				$base = pow(10, ($dec_num_length - 1 - $i));
					
				if (array_key_exists($dec_num{$i} * $base, $this->basic_numbers)) { //If the numeral is some of the basic numbers in $basic_numbers array, we just need to get that number and stop this second loop.
					$roman_num .= $this->basic_numbers[$dec_num{$i} * $base];
						
				}
				elseif ((int)$dec_num > 3999 && $i == 0) { //If the argument number is larger than 3999 and first numeral is being processed. For Roman numbers larger than 3999, a bar is often placed above number.
					$roman_num .= '<span style = "border-top: 1px solid;">' . $this->basic_numbers[$dec_num{$i}] . ' </span>';
						
				}
				elseif (in_array($dec_num{$i}, array(4, 6, 7, 8, 9))) { //If current numeral is one of those "special" numerals, which must be writen by, so called, "subtractive principle". (IIII - wrong, IV - correct; VIIII - wrong, IX - correct, and so on...)
					switch($dec_num{$i}) {
						case '4': //Prefix format for number 4.
						{								
							$roman_num .= $this->basic_numbers[$base] . $this->basic_numbers[5 * $base];								
							break;
						}					
						case '6': case '7': case '8': //Sufix format.
						{
							$roman_num .= $this->basic_numbers[5 * $base];
							for ($k = 0; $k < ((int)$dec_num{$i} - 5); $k++) {
								$roman_num .= $this->basic_numbers[$base];
							}							
							break;
						}
						case '9': //Prefix format for number 9.
						{
							$roman_num .= $this->basic_numbers[$base] . $this->basic_numbers[10 * $base];								
							break;
						}
					}					
				}
				else { //Looping until we reach the value of current numeral, beause Roman numbers can be in format "XXVII", so we need to loop 2 times for that "2" in "27", to get "XX".
					for ($j = 0; $j < (int)$dec_num{$i}; $j++) {
						$roman_num .= $this->basic_numbers[$base];
					}
				}			
			}
		}
		
		//... and here you go. :)
		return $roman_num;
	}
	
	/**
	  * Function for converting Roman to decimal numbers.
	  *
	  * @param string Roman numeral.
	  * @return int Decimal number.
	  * @access public
	  */
	public function roman2dec($rn)
	{
		$roman_num = trim($rn);
		
		//Here we go...
		$dec_num = 0;
		
		//Some special patterns that need to replaced before going into algorithm.
		$special_patterns = array('IV', 'XL', 'CD', 'IX', 'XC', 'CM', '<span style = "border-top: 1px solid;">X </span>');
		$sprecial_patterns_values = array(4, 40, 400, 9, 90, 900, 10000);
		
		if (in_array($roman_num, $this->basic_numbers)) { //If the argument is in common numbers array, there's no need to run whole algorithm.
			$key = array_keys($this->basic_numbers, $roman_num);
			return $key[0];		
		}
		
		//Replacing special patterns.
		for ($i = 0; $i < count($special_patterns); $i++) {
			if (preg_match('/' . preg_quote($special_patterns[$i], '/') .  '/', $roman_num)) {
				$roman_num = str_replace($special_patterns[$i], '', $roman_num);
				$dec_num += $sprecial_patterns_values[$i];
			}
		}
		
		$count = 1;
		for ($i = 0; $i < strlen($roman_num); $i++) {
			if ($roman_num{$i} == $roman_num{$i+1}) { //If numerals are repeating, we have to count that number of repeats.
				$count++;
			}
			else { //Getting decimal number and multply it with $count.
				$key = array_keys($this->basic_numbers, $roman_num{$i});
				$dec_num += $count * $key[0];
				$count = 1;				
			}
			
		}
		
		//... and here you go. :)
		return $dec_num;
	}
}
?>
Return current item: Dec 2 Roman Converter