Функция преобразования римских цифр

13

Создайте самую короткую функцию для преобразования строки римских цифр в целое число.

Правила для каждого письма можно найти на странице Википедии . Буквы выше 1000 будут иметь круглые скобки для обозначения их более высокого значения.

Требования:

  • Необходимо преобразовать римские цифры от 1 до 500 000
  • Должен завершиться менее чем за минуту
  • Не использует встроенные функции, которые могут обеспечить преимущество (например, функция, которая преобразует римские цифры в целые числа)
  • Это функция

Функция не должна поддерживать дроби. Любой неверный ввод должен возвращать число 0.

Кратчайшая функция выигрывает. В случае ничьей побеждает тот, у кого больше голосов.

Тестовые случаи

вход

III

Выход

3


вход

IIII

Выход

0


вход

XVI

Выход

16


вход

(C)(D)(L)MMI

Выход

452001
Кевин Браун
источник
2
Если я что-то упустил, (C)(D)(L)MMIбыло бы 452 001. Как вы получили свою ценность? Кроме того, нужно ли поддерживать «неправильные» формы (например, ICвместо XCIX)?
Анон.
Неправильный для меня означает незаконный и, следовательно, должен вернуть 0.
Мартин Йорк
@Anon: число было опечаткой, когда я изменил исходный третий контрольный пример. Не нужно поддерживать неправильные формы, так как это будет считаться неверным вводом.
Кевин Браун
1
Стандартная практика (и спецификация дубликата этого вопроса) для недопустимого ввода неверного поведения. Поскольку этому вопросу четыре года и у него был только один ответ, следует ли нам изменить требования?
lirtosiast
1
@KevinBrown Я не вижу источника или объяснения в скобках. Я думаю, что вы должны изменить спецификацию, чтобы она соответствовала codegolf.stackexchange.com/q/16254/43319 и тогда ответы оттуда можно перенести сюда.
Адам

Ответы:

6

C ++: 914 855 символов

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

Это может быть сжато дальше.

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

Немного приятнее форматирование: 1582 символа

#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";
        }
    }
}
Мартин Йорк
источник
Я не думаю, что вам нужно пространство между макро-функциями и их определениями.
Захари
4

Javascript, 317 символов

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

Explaination:

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

Без обнаружения ошибок это всего 180 символов

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

Это работает так же, но здесь лучше форматирование:

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
источник