I need to transform ordinary numbers to Roman numerals with php and I have this code:
<?php
function roman2number($roman){
$conv = array(
array("letter" => 'I', "number" => 1),
array("letter" => 'V', "number" => 5),
array("letter" => 'X', "number" => 10),
array("letter" => 'L', "number" => 50),
array("letter" => 'C', "number" => 100),
array("letter" => 'D', "number" => 500),
array("letter" => 'M', "number" => 1000),
array("letter" => 0, "number" => 0)
);
$arabic = 0;
$state = 0;
$sidx = 0;
$len = strlen($roman);
while ($len >= 0) {
$i = 0;
$sidx = $len;
while ($conv[$i]['number'] > 0) {
if (strtoupper(@$roman[$sidx]) == $conv[$i]['letter']) {
if ($state > $conv[$i]['number']) {
$arabic -= $conv[$i]['number'];
} else {
$arabic += $conv[$i]['number'];
$state = $conv[$i]['number'];
}
}
$i++;
}
$len--;
}
return($arabic);
}
function number2roman($num,$isUpper=true) {
$n = intval($num);
$res = '';
/*** roman_numerals array ***/
$roman_numerals = array(
'M' => 1000,
'CM' => 900,
'D' => 500,
'CD' => 400,
'C' => 100,
'XC' => 90,
'L' => 50,
'XL' => 40,
'X' => 10,
'IX' => 9,
'V' => 5,
'IV' => 4,
'I' => 1
);
foreach ($roman_numerals as $roman => $number)
{
/*** divide to get matches ***/
$matches = intval($n / $number);
/*** assign the roman char * $matches ***/
$res .= str_repeat($roman, $matches);
/*** substract from the number ***/
$n = $n % $number;
}
/*** return the res ***/
if($isUpper) return $res;
else return strtolower($res);
}
/* TEST */
echo $s=number2roman(6,true);
echo "\n and bacK:\n";
echo roman2number($s);
?>
try this way but does not work:
echo $s=number2roman((.$row['id'].),true);
echo "\n and bacK:\n";
echo roman2number($s);
the problem is that I need to change numbers are readings of my sql database and do not know how to, from and through.
I found this code here: http://php.net/manual/en/function.base-convert.php
Optimized and prettified function:
/**
* @param int $number
* @return string
*/
function numberToRomanRepresentation($number) {
$map = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1);
$returnValue = '';
while ($number > 0) {
foreach ($map as $roman => $int) {
if($number >= $int) {
$number -= $int;
$returnValue .= $roman;
break;
}
}
}
return $returnValue;
}
Another way to do that
<?php
function ConverToRoman($num){
$n = intval($num);
$res = '';
//array of roman numbers
$romanNumber_Array = array(
'M' => 1000,
'CM' => 900,
'D' => 500,
'CD' => 400,
'C' => 100,
'XC' => 90,
'L' => 50,
'XL' => 40,
'X' => 10,
'IX' => 9,
'V' => 5,
'IV' => 4,
'I' => 1);
foreach ($romanNumber_Array as $roman => $number){
//divide to get matches
$matches = intval($n / $number);
//assign the roman char * $matches
$res .= str_repeat($roman, $matches);
//substract from the number
$n = $n % $number;
}
// return the result
return $res;
}
echo ConverToRoman(23);
?>
function rome($N){
$c='IVXLCDM';
for($a=5,$b=$s='';$N;$b++,$a^=7)
for($o=$N%$a,$N=$N/$a^0;$o--;$s=$c[$o>2?$b+$N-($N&=-2)+$o=1:$b].$s);
return $s;
}
// from polish wiki
Check out my solution here https://github.com/frostymarvelous/Whisppa-Libs/blob/master/Misc/Numeralo.php . It works both ways.
<?php
/**
* @package Whisppa
* @subpackage Misc
* @license http://opensource.org/licenses/MIT MIT License
* @author Stefan (frostymarvelous) Froelich <sfroelich@gmail.com>
* @copyright Copyright (c) 2015, Stefan (frostymarvelous) Froelich
*/
namespace Whisppa\Misc;
/**
* This class allows you to convert from Roman numerals to natural numbers and vice versa.
* I decided to do this as a fun challenge after reading http://thedailywtf.com/articles/Roman-Enumeration
* Took me about 30 minutes to come up with, research and code the solution.
* It can convert numbers up to 3,999,999 because I couldn't find any numerals for 5,000,000 above.
* Due to my inability to get the correct accented characters 5000 above, I resulted to using the pipe (|) to represent accent.
*/
class Numeralo
{
/**
* @var string[] A notation map to represent the common Roman numeral values.
* @static
*/
protected static $NOTATION =
[
'|', //one
'[', //five
']', //ten
];
/**
* @var \ArrayObject[] A map of Roman numerals based on place value. Each item ends with the first numeral in the next place value.
* @static
*/
protected static $NUMERALS_BY_PLACE_VALUE =
[
['I', 'V', 'X',], //ones
['X', 'L', 'C',], //tens
['C', 'D', 'M',], // hundreds
['M', 'V|', 'X|',], //thousands
['X|', 'L|', 'C|',], //tens of thousands
['C|', 'D|', 'M|',], //hundreds of thousands
['M|', '~', '~',], // millions. there are no values for the last two that I could find
];
/**
* @var string[] sA map of numbers and their representative Roman numerals in notation format. This map allows us to make any numeral by replacing the the notation with the place value equivalent.
* @static
*/
protected static $NUMBER_TO_NOTATION =
[
'0' => '',
'1' => '|',
'2' => '||',
'3' => '|||',
'4' => '|[',
'5' => '[',
'6' => '[|',
'7' => '[||',
'8' => '[|||',
'9' => '|]',
];
/**
* @var int[] A map of the major Roman numerals and the number equivalent.
* @static
*/
protected static $NUMERALS_TO_NUMBER =
[
'I' => 1,
'V' => 5,
'X' => 10,
'L' => 50,
'C' => 100,
'D' => 500,
'M' => 1000,
'V|' => 5000,
'X|' => 10000,
'L|' => 50000,
'C|' => 100000,
'D|' => 500000,
'M|' => 1000000,
];
/**
* Converts natural numbers to Roman numerals.
*
* @static
* @param int|string $number a number or numeric string less than 3,999,999
* @throws \InvalidArgumentException if the provided $number argument is not numeric or greater than 3,999,999.
* @return string Roman numeral equivalent
*/
public static function number_to_numerals($number) {
if(!is_numeric($number))
throw new \InvalidArgumentException('Only numbers allowed');
if($number > 3999999)
throw new \InvalidArgumentException('Number cannot be greater than 3,999,999');
$numerals = '';
$number_string = strrev((string) $number);
$length = strlen($number_string);
for($i = 0; $i < $length; $i++) {
$char = $number_string[$i];
$num_map = self::$NUMERALS_BY_PLACE_VALUE[$i];
$numerals = str_replace(self::$NOTATION, $num_map, self::$NUMBER_TO_NOTATION[$char]) . $numerals;
}
return $numerals;
}
/**
* Converts Roman numerals to natural numbers.
*
* @static
* @param string $numerals the Roman numerals to be converted
* @throws \InvalidArgumentException if the provided $numerals argument contains invalid characters.
* @return int the equivalent number
*/
public static function numerals_to_number($numerals) {
$number = 0;
$numeral_string = strrev((string) $numerals);
$length = strlen($numeral_string);
$prev_number = false;
$is_accented = false;
for($i = 0; $i < $length; $i++) {
$char = $numeral_string[$i];
if($char == '|') //check if it is an accent character
{
$is_accented = true;
continue;//skip this iteration and process it in the next one as the accent applies to the next char
}
else if($is_accented)
{
$char .= '|';
$is_accented = false;
}
//TODO Make a check using maybe regex at the beginning of the method.
if(!isset(self::$NUMERALS_TO_NUMBER[$char]))
throw new \InvalidArgumentException("Invalid character '{$char}' in numeral string");
$num = self::$NUMERALS_TO_NUMBER[$char];
//this is where the magic happens
//if the previous number divided by 5 or 10 is equal to the current number, then we subtract eg. 9 = IX. I = 1, X = 10, 10/10 = 1
if($prev_number)
{
if(($prev_number / 5) == $num || ($prev_number / 10) == $num)
$number -= $num;
else
$number += $num;
}
else
$number += $num;
$prev_number = $num;
}
return $number;
}
}
There is an illegal offset issue.
Replace
$o=1:$b].$s);
with
$o=1:$b >0 ? $b : 0].$s);
CHECKED AND VERIFIED BY PHP UNIT
Make a class having name RomanNumerials and add a protected static property as defined:
protected static $lookup = [
1000 => 'M',
900 => 'CM',
500 => 'D',
400 => 'CD',
100 => 'C',
90 => 'XC',
50 => 'L',
40 => 'XL',
10 => 'X',
9 => 'IX',
5 => 'V',
4 => 'IV',
1 => 'I',
];
then add a method as follows
public function output ($number)
{
$solution = '';
foreach(static::$lookup as $limit => $glyph){
while ($number >= $limit) {
$solution .= $glyph;
$number -= $limit;
}
}
return $solution;
}