Saltar al contenido

Crea una calculadora de números romanos

Después de de nuestra extensa búsqueda de datos pudimos resolver esta duda que presentan muchos los lectores. Te brindamos la solución y nuestro deseo es serte de mucha apoyo.

Solución:

JavaScript (ES6), 238

c=s=>X=M:1e3,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1
n=eval('W='+s.replace(/[w]+/g,n=>(o=0,n.replace(/[MDLV]

Uso:

c("XIX + LXXX")
> "XCIX"
c('XCIX + I / L * D + IV')
> "MIV"

Versión anotada:

/**
 * Process basic calculation for roman numerals.
 * 
 * @param String s The calculation to perform
 * @return String The result in roman numerals
 */
c = s => C[MD]?

T-SQL, 1974 – 50 = 1924 bytes

Sé que jugar golf en SQL es equivalente a jugar 18 hoyos con nada más que un sand wedge, pero disfruté el desafío de este, y creo que logré hacer algunas cosas interesantes metodológicamente.

Esto admite el vinculum tanto para la entrada como para la salida. Adopté la convención de usar una tilde al final para representarlo, por lo que V ~ es 5000, X ~ es 10000, etc. También debería manejar salidas de hasta 399,999 de acuerdo con el uso estándar de números romanos modernos. Después de eso, hará una codificación romana parcialmente no estándar de cualquier cosa en el rango admitido de INT.

Debido a que todo es matemático de números enteros, cualquier resultado que no sea de números enteros se redondea implícitamente.

DECLARE @i VARCHAR(MAX)
SET @i='I+V*IV+IX*MXLVII+X~C~DCCVI'
SELECT @i

DECLARE @t TABLE(i INT IDENTITY,n VARCHAR(4),v INT)
DECLARE @u TABLE(n VARCHAR(50),v INT)
DECLARE @o TABLE(n INT IDENTITY,v CHAR(1))
DECLARE @r TABLE(n INT IDENTITY,v INT,r VARCHAR(MAX))
DECLARE @s TABLE(v INT,s VARCHAR(MAX))
DECLARE @p INT,@x VARCHAR(4000)='SELECT ',@j INT=1,@m INT,@y INT,@z VARCHAR(2),@q VARCHAR(50)='+-/*~]%'
INSERT @t(n,v) VALUES('i',1),('iv',4),('v',5),('ix',9),('x',10),('xl',50),('l',50),('xc',90),('c',100),('cd',400),('d',500),('cm',900),('m',1000),('mv~',4000),('v~',5000),('mx~',9000),('x~',10000),('x~l~',40000),('l~',50000),('x~c~',90000),('c~',100000)
INSERT @u VALUES('%i[^i'[email protected],-2),('%v[^vi'[email protected],-10),('%x[^xvi'[email protected],-20),('%l[^lxvi'[email protected],-100),('%c[^clxvi'[email protected],-200),('%d[^dclxvi'[email protected],-1000),('%mx~%',-2010),('%x~l~%',-20060),('%x~c~%',-20110)
WHILE PATINDEX('%[+-/*]%', @i)!=0
BEGIN
    SET @p=PATINDEX('%[+-/*]%', @i)
    INSERT @o(v) SELECT SUBSTRING(@i,@p,1)
    INSERT @r(r) SELECT SUBSTRING(@i,1,@p-1)
    SET @i=STUFF(@i,1,@p,'')
END 
INSERT @r(r) SELECT @i
UPDATE r SET v=COALESCE(q.v,0) FROM @r r LEFT JOIN (SELECT r.r,SUM(u.v)v FROM @u u JOIN @r r ON r.r LIKE u.n GROUP BY r.r)q ON q.r=r.r
UPDATE r SET v=r.v+q.v FROM @r r JOIN (SELECT r.n,r.r,SUM((LEN(r.r)-LEN(REPLACE(r.r,t.n,REPLICATE(' ',LEN(t.n)-1))))*t.v) v FROM @r r JOIN @t t ON CHARINDEX(t.n,r.r) != 0 AND (LEN(t.n)=1 OR (LEN(t.n)=2 AND RIGHT(t.n,1)='~')) GROUP BY r.n,r.r) q ON q.r=r.r AND q.n = r.n
SELECT @m=MAX(n) FROM @o
SELECT @[email protected]+REPLICATE('(',@m)+CAST(v AS VARCHAR) FROM @r WHERE n=1
WHILE @j<[email protected]
BEGIN
    SELECT @[email protected]+o.v+CAST(r.v AS VARCHAR)+')'
    FROM @o o JOIN @r r ON r.n=o.n+1 WHERE [email protected]
    SET @[email protected]+1
END 
INSERT @s(v,s) EXEC(@x+',''''')
UPDATE @s SET s=s+CAST(v AS VARCHAR(MAX))+' = '
SET @j=21
WHILE @j>0
BEGIN
    SELECT @y=v,@z=n FROM @t WHERE i = @j
    WHILE @y<=(SELECT v FROM @s)
    BEGIN
        UPDATE @s SET [email protected],[email protected]
    END  
    SET @[email protected]
END
SELECT @x+' = '+UPPER(s) FROM @s

Todavía estoy jugando con una solución basada en conjuntos para reemplazar algunos de los bucles WHILE que podrían reducir el recuento de bytes y ser un ejemplo más elegante de SQL idiomático. También se pueden obtener algunos bytes reduciendo el uso de alias de tabla al mínimo. Pero como es esencialmente imposible de ganar en este idioma, solo estoy aquí para mostrar mi atuendo de Don Quijote. 🙂

SELECT @i en la parte superior repite la entrada:

I+V*IV+IX*MXLVII+X~C~DCCVI

Y el SELECT al final devuelve:

SELECT (((((1+5)*4)+9)*1047)+90706) = 125257 = C~X~X~V~CCLVII

Y puede probarlo usted mismo en este SQLFiddle

Y volveré para agregar algunos comentarios sobre cómo funciona, porque ¿por qué publicar una respuesta obviamente perdedora si no la va a explotar por valor educativo?

Javascript – 482 476 caracteres

String.prototype.m=String.prototype.replace;eval("function r(a)return a>999?'Mk1e3j899?'CMk900j499?'Dk500j399?'CDk400j99?'Ck100j89?'XCk90j49?'Lk50j39?'XLk40j9?'Xk10j8?'IX':a>4?'Vk5j3?'IV':a>0?'Ik1):''".m(/k/g,"'+r(a-").m(/j/g,"):a>"));s=prompt();h=s.match(/w+/gi);for(k in h)s=s.m(h[k],eval(eval("'0'+h[k].m(/IVu4pIXu9pXLu40pXCu90pCDu400pCMu900pMu1000pDu500pCu100pLu50pXu10pVu5pIu1')".m(/u/g,"/g,'+").m(/p/g,"').m(/")))+")");for(k in h)s="("+s;alert(r(Math.floor(eval(s))))

La entrada / salida de muestra funciona:

XIX + LXXX -> XCIX
XCIX + I / L * D + IV -> MIV

También maneja mal números grandes:

MMM+MMM -> MMMMMM
M*C -> MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM

Y acepta, pero no requiere, espacios también.

Pero, como estaba jugando al golf, tiene algunos problemas:

  • No valida si la entrada está bien formada. Si la entrada no está bien formada, el comportamiento no está definido (y en la práctica es muy extraño y extraño).
  • Trunca los números de fracciones en la salida (pero puede hacer cálculos intermedios con ellos).
  • Realmente abusa de la función eval.
  • No intenta manejar números negativos.
  • Es sensible a mayúsculas y minúsculas.

Esta versión alternativa maneja números de más de 5000 hasta 99999, pero tiene 600598 584 caracteres:

String.prototype.m=String.prototype.replace;eval("function r(a)return a>8zz?'XqCqk9e4j4zz?'Lqk5e4j3zz?'XqLqk4e4jzz?'Xqk1e4j89z?'IqXqk9e3j49z?'Vqk5e3j9z?'Mk1e3j8z?'CMk900j4z?'Dk500j3z?'CDk400jz?'Ck100j89?'XCk90j49?'Lk50j39?'XLk40j9?'Xk10j8?'IX':a>4?'Vk5j3?'IV':a>0?'Ik1):''".m(/k/g,"'+r(a-").m(/j/g,"):a>").m(/q/g,"u0305").m(/z/g,"99"));s=prompt();h=s.match(/w+/gi);for(k in h)s=s.m(h[k],eval(eval("'0'+h[k].m(/IVu4pIXu9pXLu40pXCu90pCDu400pCMu900pMu1000pDu500pCu100pLu50pXu10pVu5pIu1')".m(/u/g,"/g,'+").m(/p/g,"').m(/")))+")");for(k in h)s="("+s;console.log(r(Math.floor(eval(s))))

Puntuaciones y reseñas

Recuerda que puedes permitirte agregar una reseña si te fue útil.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

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