Fonction de conversion de chiffres romains

13

Créez la fonction la plus courte pour convertir une chaîne de chiffres romains en entier.

Les règles de chaque lettre se trouvent sur la page Wikipedia . Les lettres supérieures à 1 000 auront des parenthèses placées autour d'eux pour signaler leur valeur supérieure.

Exigences:

  • Doit convertir les chiffres romains de 1 à 500 000
  • Doit terminer en moins d'une minute
  • N'utilise pas de fonctions intégrées qui pourraient fournir un avantage (Ex: une fonction qui convertit les chiffres romains en entiers)
  • Est une fonction

La fonction n'a pas besoin de prendre en charge les fractions. Toute entrée non valide doit renvoyer le chiffre 0.

La fonction la plus courte l'emporte. En cas d'égalité, celui qui a le plus de votes l'emporte.

Cas de test

Contribution

III

Production

3


Contribution

IIII

Production

0


Contribution

XVI

Production

16


Contribution

(C)(D)(L)MMI

Production

452001
Kevin Brown
la source
2
À moins que je manque quelque chose, ce (C)(D)(L)MMIserait 452 001. Comment avez-vous obtenu votre valeur? De plus, cela doit-il prendre en charge les formulaires "inappropriés" (par exemple ICau lieu de XCIX)?
Anon.
Mauvais pour moi signifie illégal et devrait donc retourner 0.
Martin York
@Anon: Le nombre était une erreur de frappe lorsque j'ai changé le troisième cas de test d'origine. Il n'a pas besoin de prendre en charge les formulaires inappropriés, car il serait considéré comme une entrée non valide.
Kevin Brown
1
La pratique standard (et la spécification du doublon de cette question) est que les entrées non valides soient un comportement non défini. Étant donné que cette question a quatre ans et n'a qu'une seule réponse, devrions-nous modifier les exigences?
lirtosiast
1
@KevinBrown Je ne vois pas de source ou d'explication pour les lettres entre parenthèses. Je pense que vous devez modifier la spécification pour qu'elle corresponde à codegolf.stackexchange.com/q/16254/43319 , puis les réponses pourront être migrées ici.
Adám

Réponses:

6

C ++: 914 855 caractères

#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";}}}

Il pourrait être encore compressé.

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

Formatage légèrement plus agréable: 1582 caractères

#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
la source
Je ne pense pas que vous ayez besoin d'un espace entre les fonctions macro et leurs définitions.
Zacharý
4

Javascript, 317 caractères

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)}

Explication:

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)
}

Sans détection d'erreur, c'est seulement 180 caractères

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'))}

Cela fonctionne de la même manière, mais voici un meilleur formatage:

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
la source