Utwórz kalkulator cyfr rzymskich

18

Utwórz podstawowy kalkulator dla cyfr rzymskich.

Wymagania

  • Podpory +, -, *,/
  • Wejścia i wyjścia należy spodziewać się tylko jednego odejmującego prefiks na symbol (czyli 3 nie może być IIV, ponieważ istnieją dwa I„s przed V)
  • Obchodzenie zasady odejmowania w wejście i wyjście musi wynosić minimum wsparcia nowoczesnych standardowych konwencji, w której tylko uprawnienia dziesiątce są odejmowane od większych liczb (np I, X, Cwymagane są subtractors ale nie V, L, D) i odejmowanie nigdy nie odbywa się od wielu więcej niż 10x odejmator (np. IXMusi być obsługiwany, ale ICnie jest wymagany).
  • Dane wejściowe i wyjściowe powinny być od lewej do prawej w kolejności od wartości, zaczynając od największej (tj. 19 = XIXnie IXX, 10 jest większe niż 9)
  • Od lewej do prawej, bez pierwszeństwa dla operatora, tak jakbyś korzystał z kalkulatora ręcznego.
  • Obsługuje wejście / wyjście całych liczb dodatnich od 1 do 4999 (nie ma potrzeby V need)
  • Brak bibliotek wykonujących konwersję cyfr rzymskich

Do decyzji

  • Rozróżnianie wielkości liter
  • Spacje lub brak spacji na wejściu
  • Co się stanie, jeśli otrzymasz wynik dziesiętny. Obcinanie, brak odpowiedzi, błąd itp.
  • Co zrobić, aby uzyskać wyjście, którego nie można obsłużyć. Negatywy lub liczby do wydrukowania.
  • Czy poprzeć bardziej liberalne stosowanie zasady odejmowania niż minimalny wymóg.

Dodatkowy kredyt

  • -50 - Uchwyt do 99999 lub większy. Symbole muszą zawierać vinculum

Przykładowe wejście / wyjście

XIX + LXXX                 (19+80)
XCIX

XCIX + I / L * D + IV      (99+1/50*500+4)
MIV

Najkrótszy kod wygrywa.

Danny
źródło
(99 + 1/50 * 500 + 4) = (99 + 10 + 4) = 113, ale przykładowe wejście / wyjście mówi, że jest to MIV (1004).
Victor Stafusa,
1
@Victor - ścisła operacja od lewej do prawej - brak reguł pierwszeństwa - więc 99 + 1/50 * 500 + 4 należy obliczać jako (((((99 + 1) / 50) * 500) + 4)
Czy obsługa numerów jest IM = 999wymagana?
Kendall Frey
@KendallFrey Spodziewałbym się, że możesz wejść IM. To, czy dane wyjściowe są, IMczy CMXCIXdla 999, zależy od Ciebie. Oba spełniają wymagania.
Danny
2
Komunikatory internetowe są niestandardowe dla współczesnych cyfr rzymskich. Zazwyczaj są to tylko 4 i 9 z każdego rzędu wielkości (4, 9, 40, 90, 400, 900 itd.), Które są wykonywane przez odejmowanie. W 1999 r. MCMXCIX byłby kanoniczny, a nie MIM ... obejrzyj kredyty każdego filmu z tego roku. W przeciwnym razie, gdzie to się skończy? Czy oczekuje się również, że będziemy obsługiwać inne niestandardowe odejmowania, takie jak VL dla 45? Czy IC z winculum nad C musiałoby być wspierane jako 99999 dla bonusu?
Jonathan Van Matre

Odpowiedzi:

9

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]|C[MD]?|X[CL]?|I[XV]?/g,d=>o+=X[d]),
o+';W=W')));o='';for(i in X)while(n>=X[i])o+=i,n-=X[i];return o}

Stosowanie:

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

Wersja z adnotacjami:

/**
 * Process basic calculation for roman numerals.
 * 
 * @param {String} s The calculation to perform
 * @return {String} The result in roman numerals
 */
c = s => {
  // Create a lookup table.
  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
  };
  // Do the calculation.
  // 
  // The evaluated string is instrumented to as below:
  //   99+1/50*500+4 -> W=99;W=W+1;W=W/50;W=W*500;W=W+4;W=W
  //                 -> 1004
  n = eval('W=' + s.replace(
    // Match all roman numerals.
    /[\w]+/g,
    // Convert the roman number into an integer.
    n => (
      o = 0,
      n.replace(
        /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g,
        d => o += X[d]
      ),
      // Instrument number to operate left-side operations.
      o + ';W=W'
    )
  ));

  // Convert the result into roman numerals.
  o = '';
  for (i in X)
    while (n >= X[i])
      o += i,
      n -= X[i];

  // Return calculation result.
  return o
}
Florent
źródło
9

T-SQL, 1974-50 = 1924 bajtów

Wiem, że gra w golfa w SQL jest równoznaczna z graniem w 18 dołków bez piasku, ale podoba mi się to wyzwanie i myślę, że udało mi się zrobić kilka interesujących rzeczy metodologicznie.

To obsługuje vinculum zarówno dla wejścia jak i wyjścia. Przyjąłem konwencję używania tylnego tylda do reprezentowania go, więc V ~ to 5000, X ~ to 10000 itp. Powinien on również obsługiwać wyjścia do 399,999 zgodnie ze standardowym nowoczesnym użyciem cyfr rzymskich. Następnie wykona częściowo niestandardowe rzymskie kodowanie czegokolwiek w obsługiwanym zakresie INT.

Ponieważ jest to matematyka w liczbach całkowitych, wyniki nie będące liczbami całkowitymi są domyślnie zaokrąglane.

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'+@q,-2),('%v[^vi'+@q,-10),('%x[^xvi'+@q,-20),('%l[^lxvi'+@q,-100),('%c[^clxvi'+@q,-200),('%d[^dclxvi'+@q,-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 @x=@x+REPLICATE('(',@m)+CAST(v AS VARCHAR) FROM @r WHERE n=1
WHILE @j<=@m
BEGIN
    SELECT @x=@x+o.v+CAST(r.v AS VARCHAR)+')'
    FROM @o o JOIN @r r ON r.n=o.n+1 WHERE o.n=@j
    SET @j=@j+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 v=v-@y,s=s+@z
    END  
    SET @j=@j-1
END
SELECT @x+' = '+UPPER(s) FROM @s

Nadal majstruję przy rozwiązaniu opartym na zestawie, aby zastąpić część pętli WHILE, która może zmniejszyć liczbę bajtów i być bardziej eleganckim przykładem idiomatycznego SQL. Istnieją również pewne bajty, które można uzyskać, ograniczając użycie aliasów tabeli do absolutnego minimum. Ale ponieważ w tym języku jest to w zasadzie niemożliwe do wygrania, jestem głównie tutaj, aby pochwalić się moim strojem Don Kichota. :)

SELECT @i u góry powtarza dane wejściowe:

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

A SELECT na końcu zwraca:

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

I możesz to przetestować sam na tym SQLFiddle

Wrócę, aby dodać komentarz na temat tego, jak to działa, ponieważ po co publikować oczywistą przegraną odpowiedź, jeśli nie zamierzasz wykorzystać jej dla wartości edukacyjnej?

Jonathan Van Matre
źródło
2

JavaScript - 482 476 znaków

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

Przykładowe wejście / wyjście działa:

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

Źle obsługuje też duże liczby:

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

I akceptuje, ale nie wymaga również spacji.

Ale odkąd grałem w golfa, ma pewne problemy:

  • Nie sprawdza poprawności, jeśli dane wejściowe są poprawnie sformułowane. Jeśli dane wejściowe nie są dobrze sformułowane, zachowanie jest niezdefiniowane (aw praktyce jest bardzo dziwne i dziwne).
  • Obcina liczby ułamkowe na wyjściu (ale jest w stanie wykonać z nimi obliczenia pośrednie).
  • To naprawdę nadużywa funkcji eval.
  • Nie próbuje obsługiwać liczb ujemnych.
  • Rozróżniana jest wielkość liter.

Ta alternatywna wersja obsługuje liczby od 5000 do 99999, ale ma 600 598 584 znaków:

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))))
Victor Stafusa
źródło
Nie sądzę, że obowiązuje -20: patrz vinculum
SeanC
Zgadzam się z @SeanCheshire tutaj. W przypadku obsługi większej liczby, intencją jest dodanie vinculum nad liczbą, która będzie 1000 razy większa niż wartość normalnie. Może powinien być większy niż -20, więc warto spróbować dla ludzi.
Danny
1
@ Danny Dodałem wersję, która obsługuje winculus, ale zwiększa kod o 116 znaków.
Victor Stafusa
2

JavaScript 479 361 348 278 253

303 znaków - 50 dla liczb obsługujących do 1 miliona, wraz z obsługą vinculum:

function p(s){s=s[r](/(^|[*\/+-])/g,"0;s$1=");for(i in v){f=R("\\b"+i);while(f.test(s))s=s[r](f,v[i]+"+")}eval(s+"0");h="";for(i in v)while(s>=v[i]){h+=i;s-=v[i]}return h}v={M̅:1e6,D̅:5e5,C̅:1e5,L̅:5e4,X̅:1e4,V̅:5e3,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};r="replace";R=RegExp

Zastosowanie: p(text)np . p('XIX + LXXX')Zwroty XCIX.

Kod z komentarzami wyjaśniającymi:

// Array mapping characters to values
v={M¯:1e6,D¯:5e5,C¯:1e5,L¯:5e4,X¯:1e4,V¯:5e3,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};
// Shortcut for String.replace
r='replace';
R=RegExp;

// The heart of the program
function p(s) {
    // Replace operators with ";s+=", ";s-=", and so on
    s=s[r](/(^|[*\/+-])/g,'0;s$1=');
    // Loop over the character map and replace all letters with numbers
    for(i in v){
        f=R('\\b'+i);
        while(f.test(s))
            s=s[r](f, v[i]+'+')
    }
    eval(s+'0');
    // Set up our return string
    h='';
    // Replace digits with characters
    for(i in v)
        while(s>=v[i]) {
            h+=i;
            s-=v[i];
        }
    return h;
}

Działa to dla podanych próbek i dla wszystkich innych próbowałem. Przykłady:

XIX + LXXX = XCIX
XCIX + I / L * D + IV = MIV
XL + IX/VII + II * XIX = CLXXI
CD + C + XL + X + I = DLI
M̅ + I = M̅I
MMMM + M = V̅
eliksenid
źródło
2

Ruby 2.1, 353 (i wiele innych iteracji) , 295-50 = 245

Obsługa vinculum dodaje ~ 23 znaki.

To obsługuje „IL” lub „VM” na wejściu i kończy się niepowodzeniem bez błędów na negatywach (przechodzi do wysokich int) lub dziesiętnych (obcina) lub dowolnych spacji. Teraz obsługuje także pierwszą ujemną liczbę (chociaż jeśli suma jest ujemna, to nadal zawodzi słabo). Nie udaje się również źle, jeśli zaczynasz od * lub / lub jeśli wynik wynosi 4 miliony lub więcej.

Używa obiektu # send dla funkcji „kalkulatora ręcznego”.

m=%w{I V X L C D M V̅ X̅ L̅ C̅ D̅ M̅};n=m.zip((0..12).map{|v|(v%2*4+1)*10**(v/2)}).to_h
d=0
gets.scan(/([-+*\/])?([A-Z̅]+)/){|o,l|f=t=0
l.scan(/.̅?/){t-=2*f if f<v=n[$&]
t+=f=v}
d=d.send o||:+,t}
7.downto(1){|v|z=10**v
y=(d%z)*10/z
q,w,e=m[v*2-2,3]
$><<(y>8?q+e : y<4?q*y : y<5?q+w : w+q*(y-5))}

Nie golfowany:

m=%w{I V X L C D M V̅ X̅ L̅ C̅ D̅ M̅} # roman numerals
n=m.zip((0..12).map{|v|(v%2*4+1)*10**(v/2)}).to_h # map symbols to values
d=0
gets. # get input and...
  scan(/([-+*\/])?([A-Z̅]+)/) { |l,o|  # for each optional operator plus number
    f=t=0
    l.scan(/.̅?/){                           # read the number in one letter at a time
      t -= 2 * f if f < (v=n[$&])           # if the number's greater than the prev, subtract the prev twice since you already added it
      t += (f = v)                          # add this, and set prev to this number
    }
    d = d.send((o || :+), t)                # now that we've built our number, "o" it to the running total (default to +)
}
7.upto(1) { |v|                        # We now print the output string from left to right
  z = 10**v                            # z = [10, 100, 1000, etc.]
  y = (d%z)*10/z                       # if d is 167 and z is 100, y = 67/10 = 6 
  q,w,e = m[v*2-2,3]                   # q,w,e = X, L, C
  $><< (                               # print: 
    y>8 ? q+e :                        # if y==9,    XC
      y<4 ? q*y :                      # if y<4,     X*y
        y>3 ? q+w :                    # if y==4,    XL
          q*(y-5)                      # else,       L + X*(y-5)
  )
}
Nie ten Charles
źródło
2

Python 2 - 427 418 404 401 396 395 392 znaków

Odczytuje ze standardowego wejścia. Obsługuje tylko wielkie litery (może powodować, że wielkość liter nie jest rozróżniana kosztem 8 dodatkowych znaków) i wymaga spacji. Nie sprawdza poprawności - nie testowałem, aby zobaczyć, jak się psuje w różnych przypadkach. Obsługuje jednak liczby takie jak VC = 95.

N=['?M','DC','LX','VI'];t=0;o='+'
for q in raw_input().split():
 if q in"+-*/":o=q;continue
 n=s=0;X=1
 for l in q:
  x=''.join(N).find(l);v=(5-x%2*4)*10**(3-x/2)
  if X<x:n+=s;s=v;X=x
  elif X>x:n+=v-s;s=0
  else:n+=v+s;s=0
 exec"t"+o+"=n+s"
r=t/1000*'M'
for p,d in enumerate("%04d"%(t%1e3)):
 i="49".find(d);g=N[p]
 if i<0:
  if'4'<d:r+=g[0]
  r+=int(d)%5*g[1]
 else:r+=g[1]+N[p-i][i]
print r

I wersja bez golfa:

# Numerals grouped by powers of 10
N = ['?M','DC','LX','VI']
# Start with zero plus whatever the first number is
t = 0
o = '+'
for q in raw_input().split():
    if q in "+-*/":
        # An operator; store it and skip to the next entry
        o = q
        continue
    # n holds the converted Roman numeral, s is a temp storage variable
    n = s = 0
    # X stores our current index moving left-to-right in the string '?MDCLXVI'
    X = 1
    for l in q:
        # x is the index of the current letter in '?MDCLXVI'
        x = ''.join(N).find(l)
        # Calculate the value of this letter based on x
        v = (5 - x%2 * 4) * 10 ** (3 - x/2)
        if X < x:
            # We're moving forward in the list, e.g. CX
            n += s      # Add in any previously-stored value
            s = v       # Store this value in case we have something like CXL
            X = x       # Advance the index
        elif X > x:
            # Moving backward, e.g. XC
            n += v - s  # Add the current value and subtract the stored one
            s=0
        else:
            # Same index as before, e.g. XX
            n += v + s  # Add the current value and any stored one
            s = 0
    # Update total using operator and value (including leftover stored value
    # if any)
    exec "t" + o + "=n+s"

# Now convert the answer back to Roman numerals
# Special-case the thousands digit
r = t / 1000 * 'M'
# Loop over the number mod 1000, padded with zeroes to four digits (to make
# the indices come out right)
for p, d in enumerate("%04d" % (t % 1e3)):
    i = "49".find(d)
    g = N[p]
    if i < 0:
        # i == -1, thus d isn't '4' or '9'
        if '4' < d:
            # >= 5, so add the 5's letter
            r += g[0]
        # ... plus (digit % 5) copies of the 1's letter
        r += int(d) % 5 * g[1]
    else:
        # If it's a 4 or 9, add the 1's letter plus the appropriate
        # larger-valued letter
        r += g[1] + N[p-i][i]
print r

Mam wrażenie, że Perl byłby lepszy, ale nie wiem o tym wystarczająco dużo. Jednak po raz pierwszy w golfa code czuję się z tym całkiem nieźle.

DLosc
źródło
1

PHP - 549 525 524 520 bajtów

Nic zbyt innowacyjnego: normalizuje operatory, aby zapewnić pierwszeństwo od lewej do prawej, konwertuje liczbę rzymską na dziesiętną, działa evalna instrukcji, np. XCIX + I / L * D + IV jest konwertowany na coś takiego jak return (((((((+90 +9)) + (+1)) / (+50)) * (+500)) + (+4)); , następnie konwertuje dziesiętne z powrotem na rzymski.

  • ostateczne wyniki są obcinane
  • odpowiedzi poniżej 1 wracają puste
  • wyniki są niezdefiniowane, jeśli podano nieprawidłowe dane wejściowe
$f='str_replace';$g='str_split';$c=array('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);$j='['.$f(array('+','-','*','/'),array('])+[','])-[','])*[','])/['), $argv[1]).'])';$j=str_repeat('(',substr_count($j,')')).$j;$j=$f('[','(',$j);$j=$f(']',')',$j);foreach($g('IVIXXLXCCDCM',2)as$w)$j=$f($w,'+'.$c[$w],$j);foreach($g('IVXLCDM')as$w)$j=$f($w,'+'.$c[$w],$j);$k=eval('return '.$j.';');$l='';foreach($c as$a=>$b){while($k>=$b){$l.=$a;$k-=$b;}}print$l."\n";

na przykład

$ php roman.php 'XCIX + I / L * D + IV' — test case
MIV                                     — 1004

$ php roman.php 'XXXII * LIX'           — 32 × 59
MDCCCLXXXVIII                           — 1888

źródło
0

Python - 446 bajtów

Można to znacznie poprawić. Czułem, że muszę zrobić pierwszy zamach używając Pythona. Robi 3 rzeczy przy pierwszym przejściu

  1. tokenizuje liczby i operatory
  2. ocenia liczby i powiększa tabelę symboli, xaby uwzględnić wszystkie możliwe napotkane kombinacje (nawet jeśli nie są używane). Na przykład, podczas gdy XIXjest lexed cząstkowe wartości "X":10, "XI":11i "XIX":19dodaje się do tablicy symboli
  3. wstawia zagnieżdżone pareny w celu wymuszenia oceny od lewej do prawej

Na koniec wywołuje evaloryginalny ciąg (oprócz dodanych parens) i nadaje mu tablicę symboli.

Potem wkleiłem tylko znane rozwiązanie konwersji liczb całkowitych na rzymskie, ponieważ pracowałem nad tym wystarczająco długo ... nie krępuj się poprawić, aby nauczyć się czegoś nowego :)

m = zip ((1000,900,500,400,100,90,50,40,10,9,5,4,1),
(„M”, „CM”, „D”, „CD”, „C”, „XC”, „L”, „XL”, „X”, „IX”, „V”, „IV”, „ JA'))
def doit (s):
 x = {„M”: 1e3, „D”: 500, „C”: 100, „L”: 50, „X”: 10, „V”: 5, „I”: 1}; y = [] ; z = ''; a = '0'; s = '+' + s
 dla cw s.upper ():
  jeśli cw x:
   z + = c; y.append (x [c])
   jeśli len (y)> 1 i y [-1]> y [-2]: y [-2] * = - 1
   x [z] = suma (y)
  elif c w „+ / * -”: a = '(' + a + z + ')' + c; y = []; z = ''
 a + = z; i = eval (a, x); r = ''
 dla n, cwm: d = int (i / n); r + = c * d; i- = n * d
 return r


print doit („XIX + LXXX”)
print doit („XCIX + I / L * D + IV”)
Mark Lakata
źródło