Buat kalkulator Angka Romawi

18

Buat kalkulator dasar untuk angka Romawi.

Persyaratan

  • Mendukung +, -, *,/
  • Input dan output harus mengharapkan hanya satu awalan subtractor per simbol (yaitu 3 tidak bisa IIVkarena ada dua Isebelumnya V)
  • Penanganan prinsip pengurangan input dan output keharusan di dukungan minimal konvensi standar modern, di mana hanya kekuatan sepuluh dikurangi dari jumlah yang lebih besar (misalnya I, X, Csubtractors diperlukan tapi tidak V, L, D) dan pengurangan tidak pernah dilakukan dari nomor lebih dari 10x subtractor (mis. IXHarus didukung tetapi ICtidak diperlukan).
  • Input dan output harus dibiarkan ke kanan dalam urutan nilai, dimulai dengan yang terbesar (yaitu 19 = XIXtidak IXX, 10 lebih besar dari 9)
  • Kiri ke kanan, tidak ada prioritas operator, seolah-olah Anda menggunakan kalkulator tangan.
  • Mendukung seluruh bilangan positif input / output antara 1-4999 (tidak perlu untuk V̅)
  • Tidak ada perpustakaan yang melakukan konversi angka romawi untuk Anda

Bagi Anda untuk memutuskan

  • Sensitivitas kasus
  • Spasi atau tidak ada spasi pada input
  • Apa yang terjadi jika Anda mendapatkan output desimal. Potong, tidak ada jawaban, kesalahan, dll.
  • Apa yang harus dilakukan untuk output yang tidak dapat Anda tangani. Negatif atau angka hingga besar untuk dicetak.
  • Apakah akan mendukung penggunaan prinsip pengurangan yang lebih liberal daripada persyaratan minimum.

Kredit tambahan

  • -50 - Tangani hingga 99999 atau lebih besar. Simbol harus menyertakan vinculum

Contoh input / output

XIX + LXXX                 (19+80)
XCIX

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

Kode terpendek menang.

Danny
sumber
(99 + 1/50 * 500 + 4) = (99 + 10 + 4) = 113, tetapi sampel input / output Anda mengatakan itu MIV (1004).
Victor Stafusa
1
@ Viktor - operasi ketat ke kanan - tidak ada aturan diutamakan - jadi 99 + 1/50 * 500 + 4 harus dihitung sebagai ((((99 + 1) / 50) * 500) + 4)
Apakah IM = 999diperlukan penanganan angka ?
Kendall Frey
@ KendallFrey Saya berharap Anda bisa memasukkan IM. Apakah outputnya IMatau CMXCIXuntuk 999 terserah Anda. Keduanya sesuai dengan persyaratan.
Danny
2
IM adalah non-standar untuk penggunaan angka Romawi modern. Biasanya hanya 4s dan 9s dari setiap urutan besarnya (4, 9, 40, 90, 400, 900, dll.) Yang dilakukan dengan pengurangan. Untuk tahun 1999, MCMXCIX akan menjadi kanonik, bukan MIM ... menonton kredit film apa pun dari tahun itu. Kalau tidak, di mana itu berakhir? Apakah kita juga diharapkan untuk mendukung pengurangan non-standar lainnya seperti VL untuk 45? Apakah IC dengan vinculum di atas C harus didukung sebagai 99999 untuk bonus?
Jonathan Van Matre

Jawaban:

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}

Pemakaian:

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

Versi beranotasi:

/**
 * 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
sumber
9

T-SQL, 1974 - 50 = 1924 byte

Saya tahu bahwa bermain golf dalam SQL sama dengan bermain 18 hole tanpa apa-apa selain sand wedge, tapi saya menikmati tantangan yang satu ini, dan saya pikir saya berhasil melakukan beberapa hal menarik secara metodologis.

Ini mendukung vinculum untuk input dan output. Saya mengadopsi konvensi menggunakan trailing tilde untuk mewakilinya, jadi V ~ adalah 5000, X ~ adalah 10000, dll. Ini juga harus menangani output hingga 399.999 menurut standar penggunaan angka Romawi modern. Setelah itu, itu akan melakukan pengkodean Romawi sebagian non-standar apa pun dalam jangkauan yang didukung INT.

Karena semuanya bilangan bulat matematika, hasil non-bilangan bulat dibulatkan secara implisit.

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

Saya masih mengutak-atik solusi berbasis set untuk menggantikan beberapa perulangan WHILE yang mungkin mengurangi jumlah byte dan menjadi contoh yang lebih elegan dari SQL idiomatik. Ada juga beberapa byte yang bisa diperoleh dengan mengurangi penggunaan alias tabel ke minimum. Tapi karena pada dasarnya ini tidak dapat dimenangkan dalam bahasa ini, saya sebagian besar hanya di sini untuk memamerkan pakaian Don Quixote saya. :)

SELECT @i di bagian atas mengulangi input:

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

Dan SELECT pada akhirnya mengembalikan:

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

Dan Anda bisa mengujinya sendiri di SQLFiddle ini

Dan saya akan kembali untuk menambahkan beberapa komentar tentang cara kerjanya, karena mengapa memposting jawaban yang jelas hilang jika Anda tidak akan memanfaatkannya untuk nilai pendidikan?

Jonathan Van Matre
sumber
2

Javascript - 482 476 karakter

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

Input / output sampel berfungsi:

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

Itu buruk menangani jumlah besar juga:

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

Dan itu menerima, tetapi tidak membutuhkan ruang juga.

Tapi, sejak saya bermain golf ada beberapa masalah:

  • Itu tidak memvalidasi jika input terbentuk dengan baik. Jika input tidak terbentuk dengan baik, perilaku tidak terdefinisi (dan dalam praktiknya sangat aneh dan aneh).
  • Ini memotong angka fraksi pada output (tetapi ia mampu melakukan perhitungan menengah dengannya).
  • Ini benar-benar menyalahgunakan fungsi eval.
  • Itu tidak berusaha menangani angka negatif.
  • Ini peka huruf besar-kecil.

Versi alternatif ini menangani angka lebih dari 5000 hingga 99999, tetapi memiliki 600 598 584 karakter:

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
sumber
Saya tidak berpikir -20 berlaku: lihat vinculum
SeanC
Setuju dengan @SeanCheshire di sini. Untuk penanganan angka yang lebih besar, tujuannya adalah menambahkan vinculum di atas angka menjadi 1000 kali lipat dari nilai normalnya. Mungkin itu harus lebih besar dari -20 sehingga membuatnya layak dicoba untuk orang.
Danny
1
@Danny Saya menambahkan versi yang menangani vinculus, tetapi meningkatkan kode dalam 116 karakter.
Victor Stafusa
2

Javascript 479 361 348 278 253

303 karakter - 50 untuk nomor pendukung hingga 1 juta, lengkap dengan dukungan 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

Penggunaan:, p(text)misalnya, p('XIX + LXXX')pengembalian XCIX.

Kode dengan komentar penjelasan:

// 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;
}

Ini berfungsi untuk sampel yang diberikan dan untuk semua orang lain yang saya coba. Contoh:

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̅
elixenide
sumber
2

Ruby 2.1, 353 (dan banyak iterasi lainnya) , 295 - 50 = 245

Penanganan vinculum menambah ~ 23 karakter.

Ini menangani "IL" atau "VM" pada input, dan gagal tanpa kesalahan negatif (masuk ke int tinggi) atau desimal (terpotong), atau spasi apa pun. Sekarang juga menangani angka pertama negatif (meskipun jika total negatif, itu masih gagal buruk). Gagal juga buruk jika Anda mulai dengan * atau / atau jika hasilnya 4 juta atau lebih besar.

Menggunakan Objek # kirim untuk fungsi "kalkulator tangan".

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

Tidak Disatukan:

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)
  )
}
Bukan itu Charles
sumber
2

Python 2 - 427 418 404 401 396 395 392 karakter

Membaca dari input standar. Ini hanya menangani huruf besar (bisa membuatnya case-sensitive dengan biaya 8 karakter tambahan) dan membutuhkan ruang. Tidak ada validasi - Saya belum menguji untuk melihat bagaimana rusak dalam berbagai kasus. Namun, ia menangani angka seperti 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

Dan versi yang tidak diserang:

# 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

Saya punya perasaan Perl akan lebih baik, tetapi saya tidak cukup tahu tentang itu. Untuk penusukan pertama pada kode golf, saya merasa cukup baik tentang ini.

DLosc
sumber
1

PHP - 549 525 524 520 byte

Tidak ada yang terlalu inovatif: menormalkan operator untuk memastikan diutamakan kiri ke kanan, mengkonversi Roman ke desimal, berjalan evalpada pernyataan, misalnya XCIX + I / L * D + IV dikonversi ke sesuatu seperti return (((((+90 +9)) + (+1)) / (+50)) * (+500)) + (+4)); , lalu mengonversi desimal kembali ke Romawi.

  • hasil akhir terpotong
  • jawaban kurang dari 1 kembali kosong
  • hasilnya tidak terdefinisi jika diberikan input yang salah
$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";

misalnya

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

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

sumber
0

Python - 446 byte

Ini dapat ditingkatkan secara signifikan. Saya merasa saya harus mengambil ayunan pertama menggunakan Python. Ia melakukan 3 hal pada pass pertama

  1. tokenizes angka dan operator
  2. mengevaluasi angka-angka, dan memperbesar tabel simbol xuntuk memasukkan semua kemungkinan kombinasi yang ditemui (bahkan jika mereka tidak digunakan). Misalnya, saat XIXsedang lexed, nilai parsial dari"X":10 , "XI":11dan "XIX":19ditambahkan ke tabel simbol
  3. menyisipkan orangtua bersarang untuk menegakkan evaluasi kiri-ke-kanan

Pada akhirnya, ia memanggil eval string asli (kecuali dengan parens yang ditambahkan) dan memberinya tabel simbol.

Lalu saya hanya menempelkan solusi yang dikenal untuk mengkonversi bilangan bulat ke Romawi, karena saya telah bekerja cukup lama ... jangan ragu untuk meningkatkan sehingga saya belajar sesuatu yang baru :)

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', ' SAYA'))
def doit:
 x = {'M': 1e3, 'D': 500, 'C': 100, 'L': 50, 'X': 10, 'V': 5, 'I': 1}; y = [] ; z = ''; a = '0'; s = '+' + s
 untuk c dalam s.upper ():
  jika c dalam x:
   z + = c; y.append (x [c])
   jika len (y)> 1 dan y [-1]> y [-2]: y [-2] * = - 1
   x [z] = jumlah (y)
  elif c dalam "+ / * -": a = '(' + a + z + ')' + c; y = []; z = ''
 a + = z; i = eval (a, x); r = ''
 untuk n, c dalam m: d = int (i / n); r + = c * d; i- = n * d
 kembali r


print doit ("XIX + LXXX")
print doit ("XCIX + I / L * D + IV")
Mark Lakata
sumber