mirror of
https://github.com/Karaka-Management/Resources.git
synced 2026-01-10 21:08:41 +00:00
137 lines
2.9 KiB
PHP
Executable File
137 lines
2.9 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Mpdf\Conversion;
|
|
|
|
/**
|
|
* @link https://github.com/JeroenDeDauw/RomanNumbers
|
|
* @license GNU GPL v2+
|
|
*/
|
|
class DecToRoman
|
|
{
|
|
|
|
private $symbolMap;
|
|
|
|
public function __construct(array $symbolMap = [])
|
|
{
|
|
if ($symbolMap !== []) {
|
|
$this->symbolMap = $symbolMap;
|
|
} else {
|
|
$this->symbolMap = [['I', 'V'], ['X', 'L'], ['C', 'D'], ['M']];
|
|
}
|
|
}
|
|
|
|
public function convert($number, $toUpper = true)
|
|
{
|
|
$this->ensureNumberIsAnInteger($number);
|
|
$this->ensureNumberIsWithinBounds($number);
|
|
|
|
return $this->constructRomanString($number, $toUpper);
|
|
}
|
|
|
|
private function ensureNumberIsAnInteger($number)
|
|
{
|
|
if (!is_int($number)) {
|
|
throw new \InvalidArgumentException('Can only translate integers to roman');
|
|
}
|
|
}
|
|
|
|
private function ensureNumberIsWithinBounds($number)
|
|
{
|
|
if ($number < 1) {
|
|
throw new \OutOfRangeException('Numbers under one cannot be translated to roman');
|
|
}
|
|
|
|
if ($number > $this->getUpperBound()) {
|
|
throw new \OutOfBoundsException('The provided number is to big to be fully translated to roman');
|
|
}
|
|
}
|
|
|
|
public function getUpperBound()
|
|
{
|
|
$symbolGroupCount = count($this->symbolMap);
|
|
$valueOfOne = 10 ** ($symbolGroupCount - 1);
|
|
|
|
$hasFiveSymbol = array_key_exists(1, $this->symbolMap[$symbolGroupCount - 1]);
|
|
|
|
return $valueOfOne * ($hasFiveSymbol ? 9 : 4) - 1;
|
|
}
|
|
|
|
private function constructRomanString($number, $toUpper)
|
|
{
|
|
$romanNumber = '';
|
|
|
|
$symbolMapCount = count($this->symbolMap);
|
|
for ($i = 0; $i < $symbolMapCount; $i++) {
|
|
$divisor = 10 ** ($i + 1);
|
|
$remainder = $number % $divisor;
|
|
$digit = $remainder / (10 ** $i);
|
|
|
|
$number -= $remainder;
|
|
$romanNumber = $this->formatDigit($digit, $i) . $romanNumber;
|
|
|
|
if ($number === 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$toUpper) {
|
|
$romanNumber = strtolower($romanNumber);
|
|
}
|
|
|
|
return $romanNumber;
|
|
}
|
|
|
|
private function formatDigit($digit, $orderOfMagnitude)
|
|
{
|
|
if ($digit === 0) {
|
|
return '';
|
|
}
|
|
|
|
if ($digit === 4 || $digit === 9) {
|
|
return $this->formatFourOrNine($digit, $orderOfMagnitude);
|
|
}
|
|
|
|
$romanNumber = '';
|
|
|
|
if ($digit >= 5) {
|
|
$digit -= 5;
|
|
$romanNumber .= $this->getFiveSymbol($orderOfMagnitude);
|
|
}
|
|
|
|
$romanNumber .= $this->formatOneToThree($orderOfMagnitude, $digit);
|
|
|
|
return $romanNumber;
|
|
}
|
|
|
|
private function formatFourOrNine($digit, $orderOfMagnitude)
|
|
{
|
|
$firstSymbol = $this->getOneSymbol($orderOfMagnitude);
|
|
$secondSymbol = $digit === 4
|
|
? $this->getFiveSymbol($orderOfMagnitude)
|
|
: $this->getTenSymbol($orderOfMagnitude);
|
|
|
|
return $firstSymbol . $secondSymbol;
|
|
}
|
|
|
|
private function formatOneToThree($orderOfMagnitude, $digit)
|
|
{
|
|
return str_repeat($this->getOneSymbol($orderOfMagnitude), $digit);
|
|
}
|
|
|
|
private function getOneSymbol($orderOfMagnitude)
|
|
{
|
|
return $this->symbolMap[$orderOfMagnitude][0];
|
|
}
|
|
|
|
private function getFiveSymbol($orderOfMagnitude)
|
|
{
|
|
return $this->symbolMap[$orderOfMagnitude][1];
|
|
}
|
|
|
|
private function getTenSymbol($orderOfMagnitude)
|
|
{
|
|
return $this->symbolMap[$orderOfMagnitude + 1][0];
|
|
}
|
|
|
|
}
|