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 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 enter 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 arguments.reduce(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

1 estrella2 estrellas3 estrellas4 estrellas5 estrellas (1 votos, promedio: 5,00 de 5)
Comparte este artículo:

Deja un comentario

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

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

Time limit is exhausted. Please reload CAPTCHA.