Skip to content

Instantly share code, notes, and snippets.

@Deuchnord
Last active August 16, 2017 11:46
Show Gist options
  • Save Deuchnord/d0e259ad11d71b43b0209875e14cec0e to your computer and use it in GitHub Desktop.
Save Deuchnord/d0e259ad11d71b43b0209875e14cec0e to your computer and use it in GitHub Desktop.
Number to Roman digits and vice-versa converter
<?php
/**
* Converts $n from Arabic digits to Roman digits.
* This is accurate from 1 to 4999 and only for integers, since the
* extensions to write the numbers greater than 4999 and the fractions are
* not implemented.
* Note that there is no way to write negative number ans zero, as they were
* not used by Roman. Plus, numbers are truncated to integers, so that 4.2
* will be converted to IV.
*
* @param integer $n
* @return string
* @throws Exception If the number cannot be converted.
**/
function arabic2roman($n) {
$n = (int) $n;
if($n < 1 || $n > 4999)
throw new Exception("Cannot convert $n to roman.");
$roman = '';
while($n >= 1000) {
$roman .= 'M';
$n -= 1000;
}
while($n >= 100) {
$roman .= 'C';
$n -= 100;
}
$roman = str_replace('CCCCCCCCC', 'CM', $roman);
$roman = str_replace('CCCCC', 'D', $roman);
$roman = str_replace('CCCC', 'CD', $roman);
while($n >= 10) {
$roman .= 'X';
$n -= 10;
}
$roman = str_replace('XXXXXXXXX', 'XC', $roman);
$roman = str_replace('XXXXX', 'L', $roman);
$roman = str_replace('XXXX', 'XL', $roman);
while($n > 0) {
$roman .= 'I';
$n -= 1;
}
$roman = str_replace('IIIIIIIII', 'IX', $roman);
$roman = str_replace('IIIII', 'V', $roman);
$roman = str_replace('IIII', 'IV', $roman);
return $roman;
}
/**
* Converts $n from Roman digits to a number.
*
* @param string $n
* @param int The number which corresponds to $n
* @throws Exception If the number cannot be converted (especially because
* of a parse error)
**/
function roman2arabic($n) {
$arabic = 0;
$pos = 0;
$n = strtoupper($n);
for($i = 0; $i < strlen($n); $i++) {
$digit = $n[$i];
$nextdigit = $n[$i+1];
switch($digit) {
case 'I':
if($nextdigit == 'X') {
$arabic += 9;
$i++;
continue;
}
elseif($nextdigit == 'V') {
$arabic += 4;
$i++;
continue;
}
$arabic += 1;
break;
case 'V':
$arabic += 5;
break;
case 'X':
if($nextdigit == 'L') {
$arabic += 40;
$i++;
continue;
}
if($nextdigit == 'C') {
$arabic += 90;
$i++;
continue;
}
$arabic += 10;
break;
case 'L':
$arabic += 50;
break;
case 'C':
if($nextdigit == 'D') {
$arabic += 400;
$i++;
continue;
}
if($nextdigit == 'M') {
$arabic += 900;
$i++;
continue;
}
$arabic += 100;
break;
case 'D':
$arabic += 500;
break;
case 'M':
$arabic += 1000;
break;
default:
throw new Exception("Parse error: $digit is not a valid Roman digit.");
}
}
return $arabic;
}
header('Content-Type: text/plain');
for($i=1;$i<5000;$i++)
echo arabic2roman($i) . ' <=> ' . roman2arabic(arabic2roman($i)) . "\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment