Números romanos en JavaScript

Hace algunos años desarrollé una pequeña clase en Action Script 3 para trabajar con números romanos mediante expresiones regulares, como Action Script ha caído en la debacle que todos conocemos y está reservado casi exclusivamente para el desarrollo de videojuegos, decidí portar esta clase a JavaScript.

A pesar de que los números romanos ya están en desuso y es muy extraño que hoy en día alguien requiera utilizarlos, creo que siempre habrá alguien al que le será útil contar con una herramienta que haga este trabajo de manera sencilla.

Este código está preparado para trabajar con números hasta 3’999’999 por lo que cualquier valor que sobrepase esta cantidad arribará en un error de ejecución. Para los números mayores de 3’999 se utilizó la notación de entre paréntesis para indicar que la base de multiplicación es 1’000.

Números romanos en JavaScript

var RomanNumbers = function() {

	var _letters = ["I", "V", "X", "L", "C", "D", "M", "(V)", "(X)", "(L)", "(C)", "(D)", "(M)"];
	var _regexp = /^((\(M\)){0,3})(\(C\)\(M\)|\(C\)\(D\)|(\(D\))?(\(C\)){0,3})(\(X\)\(C\)|\(X\)\(L\)|(\(L\))?(\(X\)){0,3})(M\(X\)|M\(V\)|(\(V\))?)(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/;

	//---Método de hacer un test del número romano
	this.testRoman = function(roman) {

		return _regexp.test(roman);

	}

	//---Método de obtener un número romano
	this.getRomanNumber = function(number) {

		if (number > 3999999) throw "Numbers higher than 3999999 can't be converted to Roman. Try a lower value!";

		var roman = "";
		var cant = String(number).length;
		var narray = String(number).split("").reverse();

		var parser = function(item, index, a) {
            
			switch(item) {

				case "0":
				case "1":
				case "2":
				case "3":
					roman = (new Array(Number(item) + 1).join(_letters[index * 2])) + roman;
				break;

				case "4":
					roman = _letters[index * 2] + _letters[index * 2 + 1] + roman;
				break;

				case "5":
				case "6":
				case "7":
				case "8":
					roman = _letters[index * 2 + 1] + (new Array(Number(item) - 4).join(_letters[index * 2])) + roman;
				break;

				case "9":
					roman = _letters[index * 2] + _letters[index * 2 + 2] + roman;
				break;

			}

		}

		narray.forEach(parser);

		return roman;

	}

	//---Método de obtener el número arábigo
	this.getArabicNumber = function (roman) {

		if (!this.testRoman(roman)) throw "You have entered an invalid roman number. Please try with another value";

		var reg = /(\()(\w)(\))/g;
		var simple = "";
		var values = 0;
		var array = _regexp.exec(roman);

		array.splice(0, 1);
		array.splice(1, 1);
		array.splice(2, 2);
		array.splice(3, 2);
		array.splice(4, 1);

		var parser = function(item, index, a) {

			switch(index){

				case 0:
				case 1:
				case 2:
					simple = item.replace(reg, "$2");
					values += getValue(simple) * 1000;
				break;

				case 3:
					simple = item.replace(reg, "$2");
					values += ((simple.slice(0, 1) == "M") ? getValue(simple.slice(1, 2)) * 1000 - getValue(simple.slice(0, 1)) : getValue(simple) * 1000);
				break;

				case 4:
				case 5:
				case 6:
				case 7:
					values += getValue(item);
				break;

			}

		}

		array.forEach(parser);

		return values;

	}

	//---Función de devolver un número a partir de un string romano
	function getValue(str) {

		var cant = str.length;
		var chars = [];
		var ret = 0;

		switch(cant) {

			case 1:
				ret = getNumberByIndex(_letters.indexOf(str));
			break;

			case 2:
				chars = str.split("");
				ret = ((_letters.indexOf(chars[0]) < _letters.indexOf(chars[1])) ? getNumberByIndex(_letters.indexOf(chars[1])) - getNumberByIndex(_letters.indexOf(chars[0])) : getNumberByIndex(_letters.indexOf(chars[0])) + getNumberByIndex(_letters.indexOf(chars[1])));
			break;

			case 3:
				chars = str.split("");
				ret = sumAllNumbers(getNumberByIndex(_letters.indexOf(chars[0])), getNumberByIndex(_letters.indexOf(chars[1])), getNumberByIndex(_letters.indexOf(chars[2])));
			break;

			case 4:
				chars = str.split("");
				ret = sumAllNumbers(getNumberByIndex(_letters.indexOf(chars[0])), getNumberByIndex(_letters.indexOf(chars[1])), getNumberByIndex(_letters.indexOf(chars[2])), getNumberByIndex(_letters.indexOf(chars[3])));
			break;

		}

		return ret;

	}

	//---Retornar un número de acuerdo a su index en el arreglo de letras
	function getNumberByIndex(index) {
		return ((index % 2 == 0) ? Math.pow(10, index / 2) : Math.pow(10, (index + 1) / 2) / 2);
	}

	//---Función de sumar varios números
	function sumAllNumbers() {

		return Array.prototype.reduce.call(arguments, function (s, n) {
			return s + n;
		}, 0);

	}

}
Métodos
// Método de devolver un número romano a partir de un arábigo
getRomanNumber(int $number)
$number Número entero que se desea convertir a romano
// Método de devolver un número arábigo a partir de un romano
getArabicNumber(string $roman)
$roman Cadena que representa al número romano para convertirlo en arábigo. Si se desea trabajar con número superiores a 1’000 se deben representar entre paréntesis (Ej. (V) = 5’000)
// Método de chequear si el número romano enviado es correcto
boolean testRoman(string $roman)
$roman Cadena que representa al número romano para comprobar si es correcto

Ejemplo de código

var manager = new RomanNumbers();
manager.testRoman("CCX"); // true
manager.testRoman("XXCC"); // false
manager.getRomanNumber(4529); // M(V)DXXIX
manager.getArabicNumber("M(X)IV"); // 9004

Demo del trabajo con números romanos en JavaScript

Demo

Descarga los ficheros

Descargar

(2 votos, promedio: 5,00 de 5)
Comparte este artículo:

2 Comentarios

    • Hola HenryB:
      Si descargas los ficheros o consultas el código de la demostración, encontrarás un ejemplo para hacer lo que deseas. Aquí te dejo el fragmento relevante de código JavaScript:

      window.onload = function(){
      
      	//---Declaración de variables
      	var arabic = document.getElementById("arabic");
      	var roman = document.getElementById("roman");
      	var manager = new RomanNumbers();
      
      	arabic.addEventListener("change", convertToRoman);
      	arabic.addEventListener("keyup", convertToRoman);
      
      	roman.addEventListener("change", convertToArabic);
      	roman.addEventListener("keyup", convertToArabic);
      
      	//---Convertir a romano
      	function convertToRoman(){
      		roman.value = (Number(arabic.value) < 3999999) ? manager.getRomanNumber(Number(arabic.value)) : "El número arábigo no es válido";
      	}
      
      	//---Convertir a arábigo
      	function convertToArabic(){
      		arabic.value = (manager.testRoman(roman.value)) ? manager.getArabicNumber(roman.value) : "El número romano no es válido";
      	}
      
      }
      

      Un saludo

Puedes situar fragmentos de código dentro de etiquetas <pre></pre> y código HTML o XML entre etiquetas <xmp></xmp>.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *


El periodo de verificación de reCAPTCHA ha caducado. Por favor, recarga la página.