Función de convertidor de números romanos

13

Cree la función más corta para convertir una cadena de números romanos en un número entero.

Las reglas para cada letra se pueden encontrar en la página de Wikipedia . Las letras por encima de 1,000 tendrán paréntesis alrededor de ellas para indicar su valor más alto.

Requisitos:

  • Debe convertir los números romanos del 1 al 500,000
  • Debe completarse en menos de un minuto.
  • No utiliza funciones integradas que podrían proporcionar una ventaja (Ej: Una función que convierte números romanos en enteros)
  • Es una funcion

La función no necesita admitir fracciones. Cualquier entrada no válida debe devolver el número 0.

La función más corta gana. En caso de empate, gana el que tenga más votos.

Casos de prueba

Entrada

III

Salida

3


Entrada

IIII

Salida

0


Entrada

XVI

Salida

16


Entrada

(C)(D)(L)MMI

Salida

452001
Kevin Brown
fuente
2
A menos que me falte algo, (C)(D)(L)MMIserían 452.001. ¿Cómo obtuviste tu valor? Además, ¿esto debe admitir formas "incorrectas" (por ejemplo, en IClugar de XCIX)?
Anon
Incorrecto para mí significa ilegal y, por lo tanto, debería devolver 0.
Martin York
@Anon: El número era un tipo incorrecto de cuando cambié el tercer caso de prueba original. No necesita admitir formularios incorrectos, ya que se consideraría una entrada no válida.
Kevin Brown
1
La práctica estándar (y la especificación del duplicado de esta pregunta) es que la entrada no válida sea un comportamiento indefinido. Dado que esta pregunta tiene cuatro años y solo tenía una respuesta, ¿deberíamos cambiar los requisitos?
lirtosiast
1
@KevinBrown No veo una fuente o explicación para las letras entre paréntesis. Creo que debería cambiar la especificación para que coincida con codegolf.stackexchange.com/q/16254/43319 y luego las respuestas desde allí se pueden migrar aquí.
Adám

Respuestas:

6

C ++: 914 855 caracteres

#include<map>
#include<string>
#include<iostream>
#include<sstream>
#define I istream
#define T(C) if(C)throw int(1);
#define X(c,v,f,m) D[c]=v;P[c]=D[f];M[c]=m;
#define S second
using namespace std;typedef map<char,int>R;R D,P,M;struct U{U():t(0),l(0),a(0){}int t,l,a;operator int(){return t+l;}I&d(I&s){char c,b;s>>c;if(c=='('){s>>c>>b;T(b!=')')c+=32;}if(s){R::iterator f=D.find(c);T(f==D.end())if(P[c]==l){l=f->S-l;a=0;}else{T(l&&(f->S>l))a=l==f->S?a+1:1;T(a>M[c])t+=l;l=f->S;}}return s;}};I&operator>>(I&s,U&d){return d.d(s);}int main(){D[' ']=-1;X(73,1,32,3)X(86,5,73,1)X(88,10,73,3)X(76,50,88,1)X(67,100,88,3)X(68,500,67,1)X(77,1000,67,3)X(118,5000,77,1)X(120,10000,77,3)X(108,50000,120,1)X(99,100000,120,3)X(100,500000,99,1)X(109,1000000,99,3)string w;while(cin>>w){try{stringstream s(w);U c;while(s>>c);cout<<c<<"\n";}catch(int x){cout<<"0\n";}}}

Podría ser comprimido aún más.

> ./a.exe
III
3
IIII
0
XVI
16
(C)(D)(L)MMI
452001

Formato ligeramente más agradable: 1582 char

#include<map>
#include<string>
#include<iostream>
#include<sstream>
#define I istream
#define T(C) if(C)throw int(1);
#define X(c,v,f,m) D[c]=v;P[c]=D[f];M[c]=m;
#define S second
using namespace std;

typedef map<char,int>      R;

R     D,P,M;

struct U
{
    U(): t(0), l(0), a(0) {}

    int  t,l,a;

    operator int()
    {
        return t + l;
    }
    I& d(I& s)
    {
        char c,b;
        s >> c;
        if (c == '(')
        {
            s >> c >> b;
            T(b != ')')
            c = tolower(c);
        }
        if (s)
        {
            R::iterator f = D.find(c);
            T(f == D.end())

            if (P[c] == l)
            {
                l = f->S - l;
                a = 0;
            }
            else
            {
                T(l&&(f->S > l))
                a=l==f->S?a+1:1;
                T(a>M[c])
                t   += l;
                l     = f->S;
            }
        }

        return s;
    }

};

I& operator>>(I& s,U& d)
{
    return d.d(s);
}

int main()
{
    D[' ']=-1;
    X(73,1,32,3)
    X(86,5,73,1)
    X(88,10,73,3)
    X(76,50,88,1)
    X(67,100,88,3)
    X(68,500,67,1)
    X(77,1000,67,3)
    X(118,5000,77,1)
    X(120,10000,77,3)
    X(108,50000,120,1)
    X(99,100000,120,3)
    X(100,500000,99,1)
    X(109,1000000,99,3)

    string w;
    while(cin >> w)
    {
        try
        {
            stringstream s(w);
            U    c;
            while(s >> c);
            cout << c << "\n";
        }
        catch(int x)
        {
            cout << "0\n";
        }
    }
}
Martin York
fuente
No creo que necesite un espacio entre las funciones macro y sus definiciones.
Zacharý
4

Javascript, 317 caracteres

function f(s){for(r=/\(?(.\)?)/g,t=e=0;a=r.exec(s);l=a[0].length,d='IXCMVLD'.indexOf(a[1][0]),e=e||d<0||l==2||d*4+l==3,t+='+'+(d>3?5:1)*Math.pow(10,d%4+3*(l>1)));t=t&&t.replace(/1(0*).(10|5)\1(?!0)/g,'$2$1-1$1');return e||/[^0](0*)\+(10|5)\1/.test(t)||/(\+10*)\1{3}(?!-)/.test(t)||/-(10*)\+\1(?!-)/.test(t)?0:eval(t)}

Explicación:

function f(s){
      // iterate over every character grabbing parens along the way
  for(r=/\(?(.\)?)/g,t=e=0;a=r.exec(s);    
        // get a numerical value for each numeral and join together in a string
    l=a[0].length,
    d='IXCMVLD'.indexOf(a[1][0]),
    e=e||d<0||l==2||d*4+l==3,    // find invalid characters, and parens
    t+='+'+(d>3?5:1)*Math.pow(10,d%4+3*(l>1))
  );
      // reorder and subtract to fix IV, IX and the like
  t=t&&t.replace(/1(0*).(10|5)\1(?!0)/g,'$2$1-1$1');
  return e||
    /[^0](0*)\+(10|5)\1/.test(t)|| // find VV,IIV,IC,...
    /(\+10*)\1{3}(?!-)/.test(t)||  // find IIII,... but not XXXIX
    /-(10*)\+\1(?!-)/.test(t)      // find IVI,... but not XCIX
      ?0:eval(t)
}

Sin detección de errores solo son 180 caracteres

function g(s){for(r=/\(?(.\)?)/g,t=0;a=r.exec(s);d='IXCMVLD'.indexOf(a[1][0]),t+='+'+(d>3?5:1)+'0'.repeat(d%4+3*(a[1].length>1)));return eval(t.replace(/(1(0*).(10|5)\2)/g,'-$1'))}

Esto funciona de la misma manera, pero aquí hay un mejor formato:

function g(s){
  for(r=/\(?(.\)?)/g,t=0;a=r.exec(s);
    d='IXCMVLD'.indexOf(a[1][0]),
    t+='+'+(d>3?5:1)+'0'.repeat(d%4+3*(a[1].length>1))
  );
  return eval(t.replace(/(1(0*).(10|5)\2)/g,'-$1'))
}
BlueCheetah
fuente