<?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;
 
    }
 
}
 
 |