| 
<?php
/**
 * Dec2RomanNumConverter
 *
 * Copyright (C) 2009 Nikola Posa (http://www.nikolaposa.in.rs)
 *
 * This file is part of Dec2RomanNumConverter.
 *
 * Dec2RomanNumConverter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Dec2RomanNumConverter is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Dec2RomanNumConverter. If not, see <http://www.gnu.org/licenses/>.
 */
 
 /**
 * Class for converting decimal numbers to Roman numberals and
 * vice-versa.
 *
 * @author Nikola Posa, www.nikolaposa.in.rs
 * @license http://opensource.org/licenses/gpl-3.0.html GNU General Public License
 */
 class Dec2RomanNumConverter
 {
 /**
 * Common Roman numerals array, with appropriate decimal
 * numbers as indexes.
 *
 * @var array
 */
 protected static $_basicNumbers = array
 (
 1    => 'I',
 5    => 'V',
 10   => 'X',
 50   => 'L',
 100  => 'C',
 500  => 'D',
 1000 => 'M'
 );
 
 /**
 * Method for converting decimal numbers to Roman numerals.
 *
 * @param int $decimalNumber
 * @return string
 */
 public static function dec2roman($decimalNumber)
 {
 $decimalNumber = (int)$decimalNumber;
 
 //Cheks if argument is larger than 3999 as such numbers
 //require a bar above the base numeral.
 if ($decimalNumber > 3999) {
 require_once 'Dec2RomanNumConverter/Exception.php';
 throw new Dec2RomanNumConverter_Exception('Numbers larger than 3999 are not supported.');
 }
 
 if (array_key_exists($decimalNumber, self::$_basicNumbers)) {
 return self::$_basicNumbers[$decimalNumber];
 }
 
 $romanNum = '';
 
 $decNum = (string)$decimalNumber;
 $decNumLength = strlen($decNum);
 
 for ($i = 0; $i < $decNumLength; $i++) { //Looping through all numerals.
 $currentNumber = (int)$decNum[$i];
 if ($currentNumber == 0) {
 continue;
 }
 
 $decPow = pow(10, ($decNumLength - 1 - $i));
 
 switch ($currentNumber) {
 case 4: case 9: //4 and 9 are written using their higher base (5 or 10).
 $romanNum .=
 self::$_basicNumbers[$decPow]
 . self::$_basicNumbers[($currentNumber+1)*$decPow];
 break;
 case 6: case 7: case 8: //4 and 9 are written using 5 (V) as a base.
 $romanNum .=
 self::$_basicNumbers[5*$decPow]
 . str_repeat(self::$_basicNumbers[$decPow], ($currentNumber-5));
 break;
 case 5:
 $romanNum .= self::$_basicNumbers[5*$decPow];
 break;
 default:
 $romanNum .= str_repeat(self::$_basicNumbers[$decPow], $currentNumber);
 break;
 }
 }
 
 return $romanNum;
 }
 
 /**
 * Method for converting Roman numerals to decimal numbers.
 *
 * @param string $romanNumeral
 * @return int
 */
 public static function roman2dec($romanNumeral)
 {
 $romanNumeral = trim((string)$romanNumeral);
 if (!preg_match('/^[' . implode('', array_values(self::$_basicNumbers)) . ']+$/i', $romanNumeral)) {
 require_once 'Dec2RomanNumConverter/Exception.php';
 throw new Dec2RomanNumConverter_Exception('Roman numeral "' . $romanNumeral . '" is not valid or it is to large to handle.');
 }
 
 $romanNumeral = strtoupper($romanNumeral);
 
 $decNum = 0;
 
 //Early return.
 if (($decNum = array_search($romanNumeral, self::$_basicNumbers)) !== false) {
 return $decNum;
 }
 
 $count = 1;
 $basicNumbers = array_flip(self::$_basicNumbers);
 for ($i = 0; $i < strlen($romanNumeral); $i++) {
 $dn = $basicNumbers[$romanNumeral[$i]];
 $nextDn = (isset($romanNumeral[$i+1])) ? $basicNumbers[$romanNumeral[$i+1]] : null;
 
 $decNum += $dn;
 
 if ($nextDn !== null) {
 if ($nextDn == $dn) {
 $count++;
 }
 elseif ($nextDn > $dn) { //Special pattern (IV, IX, CM, etc.)?
 $temp = $dn * $count; //Value that will be substracted from higher base.
 $decNum -= $temp;
 $decNum += $nextDn - $temp;
 
 $i++; //Skipping next numeral.
 $count = 1;
 }
 else {
 $count = 1;
 }
 }
 }
 
 return $decNum;
 }
 }
 |