romanos para numeros naturales flujo diagrama decimales convertir arabigos algoritmo php integer roman-numerals

php - para - numeros romanos



¿Cómo convertir un número romano a entero en PHP? (11)

¡Define tu propio esquema! (Opcional)

function rom2arab($rom,$letters=array()){ if(empty($letters)){ $letters=array(''M''=>1000, ''D''=>500, ''C''=>100, ''L''=>50, ''X''=>10, ''V''=>5, ''I''=>1); }else{ arsort($letters); } $arab=0; foreach($letters as $L=>$V){ while(strpos($rom,$L)!==false){ $l=$rom[0]; $rom=substr($rom,1); $m=$l==$L?1:-1; $arab += $letters[$l]*$m; } } return $arab; }

Inspirado por la respuesta de andyb.

Usando PHP, me gustaría convertir una cadena que contiene un número romano en su representación entera. Necesito esto porque necesito hacer cálculos sobre ellos.

Wikipedia en números romanos

Bastaría con reconocer solo los caracteres del número romano básico, como:

$roman_values=array( ''I'' => 1, ''V'' => 5, ''X'' => 10, ''L'' => 50, ''C'' => 100, ''D'' => 500, ''M'' => 1000, );

Eso significa que el número más alto posible es 3999 (MMMCMXCIX). Usaré N para representar cero, aparte de que solo se admiten los enteros positivos.

No puedo usar la biblioteca PEAR para los números romanos.

Encontré esta gran pregunta en SO sobre cómo probar si la cadena contiene un número romano válido:

¿Cómo se relacionan solo los números romanos válidos con una expresión regular?

¿Cuál sería la mejor manera de codificar esto?


Acabo de escribir esto en unos 10 minutos, no es perfecto, pero parece funcionar para los pocos casos de prueba que le he dado. No estoy aplicando qué valores se pueden restar de qué, esto es solo un bucle básico que compara el valor de letra actual con el siguiente en la secuencia (si existe) y luego agrega el valor o agrega la cantidad sustraída al total:

$roman = strtolower($_GET[''roman'']); $values = array( ''i'' => 1, ''v'' => 5, ''x'' => 10, ''l'' => 50, ''c'' => 100, ''d'' => 500, ''m'' => 1000, ); $total = 0; for($i=0; $i<strlen($roman); $i++) { $v = $values[substr($roman, $i, 1)]; $v2 = ($i < strlen($roman))?$values[substr($roman, $i+1, 1)]:0; if($v2 && $v < $v2) { $total += ($v2 - $v); $i++; } else $total += $v; } echo $total;


Este es el que se me ocurrió, también agregué la verificación de validez.

class RomanNumber { //array of roman values public static $roman_values=array( ''I'' => 1, ''V'' => 5, ''X'' => 10, ''L'' => 50, ''C'' => 100, ''D'' => 500, ''M'' => 1000, ); //values that should evaluate as 0 public static $roman_zero=array(''N'', ''nulla''); //Regex - checking for valid Roman numerals public static $roman_regex=''/^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/''; //Roman numeral validation function - is the string a valid Roman Number? static function IsRomanNumber($roman) { return preg_match(self::$roman_regex, $roman) > 0; } //Conversion: Roman Numeral to Integer static function Roman2Int ($roman) { //checking for zero values if (in_array($roman, self::$roman_zero)) { return 0; } //validating string if (!self::IsRomanNumber($roman)) { return false; } $values=self::$roman_values; $result = 0; //iterating through characters LTR for ($i = 0, $length = strlen($roman); $i < $length; $i++) { //getting value of current char $value = $values[$roman[$i]]; //getting value of next char - null if there is no next char $nextvalue = !isset($roman[$i + 1]) ? null : $values[$roman[$i + 1]]; //adding/subtracting value from result based on $nextvalue $result += (!is_null($nextvalue) && $nextvalue > $value) ? -$value : $value; } return $result; } }


Idea rápida: recorra el número romano de derecha a izquierda, si el valor de $current (más a la izquierda) es menor que $previous , luego reste el resultado, si es mayor, luego agréguelo.

$romanValues=array( ''I'' => 1, ''V'' => 5, ''X'' => 10, ''L'' => 50, ''C'' => 100, ''D'' => 500, ''M'' => 1000, ); $roman = ''MMMCMXCIX''; // RTL $arabic = 0; $prev = null; for ( $n = strlen($roman) - 1; $n >= 0; --$n ) { $curr = $roman[$n]; if ( is_null($prev) ) { $arabic += $romanValues[$roman[$n]]; } else { $arabic += $romanValues[$prev] > $romanValues[$curr] ? -$romanValues[$curr] : +$romanValues[$curr]; } $prev = $curr; } echo $arabic, "/n"; // LTR $arabic = 0; $romanLength = strlen($roman); for ( $n = 0; $n < $romanLength; ++$n ) { if ( $n === $romanLength - 1 ) { $arabic += $romanValues[$roman[$n]]; } else { $arabic += $romanValues[$roman[$n]] < $romanValues[$roman[$n+1]] ? -$romanValues[$roman[$n]] : +$romanValues[$roman[$n]]; } } echo $arabic, "/n";

También se debe agregar alguna validación del número romano, aunque usted dijo que ya ha encontrado cómo hacerlo.


Llego tarde a la fiesta, pero aquí está la mía. Asume números válidos en la cadena, pero no prueba un número romano válido, sea lo que sea ... no parece haber consenso. Esta función funcionará para números romanos como VC (95), o MIM (1999), o MMMMMM (6000).

function roman2dec( $roman ) { $numbers = array( ''I'' => 1, ''V'' => 5, ''X'' => 10, ''L'' => 50, ''C'' => 100, ''D'' => 500, ''M'' => 1000, ); $roman = strtoupper( $roman ); $length = strlen( $roman ); $counter = 0; $dec = 0; while ( $counter < $length ) { if ( ( $counter + 1 < $length ) && ( $numbers[$roman[$counter]] < $numbers[$roman[$counter + 1]] ) ) { $dec += $numbers[$roman[$counter + 1]] - $numbers[$roman[$counter]]; $counter += 2; } else { $dec += $numbers[$roman[$counter]]; $counter++; } } return $dec; }


Los derechos de autor son para este blog (¡por cierto!) http://scriptsense.blogspot.com/2010/03/php-function-number-to-roman-and-roman.html

<?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(1965,true); echo "/n and bacK:/n"; echo roman2number($s); ?>


No estoy seguro de si tienes ZF o no, pero en caso de que tú (o cualquiera de ustedes que está leyendo esto) lo hagas aquí es mi fragmento:

$number = new Zend_Measure_Number(''MCMLXXV'', Zend_Measure_Number::ROMAN); $number->convertTo (Zend_Measure_Number::DECIMAL); echo $number->getValue();


Qué tal esto:

$romans = 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, ); $roman = ''MMMCMXCIX''; $result = 0; foreach ($romans as $key => $value) { while (strpos($roman, $key) === 0) { $result += $value; $roman = substr($roman, strlen($key)); } } echo $result;

que debe dar salida a 3999 para el $roman suministrado. Parece funcionar para mis pruebas limitadas:

MCMXC = 1990 MM = 2000 MMXI = 2011 MCMLXXV = 1975

Es posible que desee hacer una validación primero también :-)


Simplemente tropecé con esta belleza y tengo que publicarla por todas partes:

function roman($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; }


function Romannumeraltonumber($input_roman){ $di=array(''I''=>1, ''V''=>5, ''X''=>10, ''L''=>50, ''C''=>100, ''D''=>500, ''M''=>1000); $result=0; if($input_roman=='''') return $result; //LTR for($i=0;$i<strlen($input_roman);$i++){ $result=(($i+1)<strlen($input_roman) and $di[$input_roman[$i]]<$di[$input_roman[$i+1]])?($result-$di[$input_roman[$i]]) :($result+$di[$input_roman[$i]]); } return $result; }


function rom_to_arabic($number) { $symbols = array( ''M'' => 1000, ''D'' => 500, ''C'' => 100, ''L'' => 50, ''X'' => 10, ''V'' => 5, ''I'' => 1); $a = str_split($number); $i = 0; $temp = 0; $value = 0; $q = count($a); while($i < $q) { $thys = $symbols[$a[$i]]; if(isset($a[$i +1])) { $next = $symbols[$a[$i +1]]; } else { $next = 0; } if($thys < $next) { $value -= $thys; } else { $value += $thys; } $temp = $thys; $i++; } return $value; }