Bir ifadeyi parantez içine alma


20

Son zamanlarda yeni bir dil yazıyorum , işlem sırasını ele almayı önlemek için zorunda kalmamak için, bunu tamamen önlemek için her ifadeyi uygun şekilde parantez içine alıyorum.

Parantez karakter kodları 40-41'de olduğundan, kodunuzun mümkün olduğunca kısa olması gerekir.


Örnekler

1+2*3
(1+(2*3))

2*(3+4)
(2*(3+4))

2*3/4+3
(((2*3)/4)+3)

342*32/8
((342*32)/8)

kurallar

Yapmanız gereken tek işlem şunlardır: *(çarpma), /(bölme), +(toplama) ve -(çıkarma).

  • İşlem sırası :
    • Parantez
    • Çarpma, Bölme
    • Toplama, Çıkarma
  • Sola-sağa gitmeyi tercih etmelisin
  • Giriş numaraları her zaman pozitif tamsayılar olacaktır (bonuslara bakınız)

Bonuslar

Olumsuzluğu ele alırsanız % -20 :

3+-5
(3+(-5))

Girdinin içine boşluk yerleştirilmesine izin verirseniz % -5 :

3  + 4
(3+4)

Girişte ondalık basamakları işleyebiliyorsanız % -10 :

1+.12
(1+.12)
1+0.21/3
(1+(0.21/3))

500 ödül: Eğer bir cevap yazmak için yönetiyorsanız Adsız / Blokları


25
"Parantez 40-41 karakter kodunda olduğundan, kodunuzun mümkün olduğunca kısa olması gerekir." Tamam, şimdi sadece saçma oluyorsun. ; P
ETHproductions

3
Ve bu önek (Lehçe) notasyonundan daha kolaydır, çünkü?
wizzwizz4

3
Olası kopya .
flawr

8
@flawr Bunu gördüm, ancak bu sorunun bir ifadeyi parantez içine almanın tüm yollarını ortaya çıkarması çok farklı. Burada kod bu zorluk için önemsiz bir şekilde değiştirilemediğinden, önemli bir fark olduğunu düşündüğüm işlem sırasını dikkate
almalısınız

3
Önemli test örneği: 1+2+3+4(bazı çözümler parantez içinde olabilir ((1+2)+(3+4)))
Martin Ender

Yanıtlar:


2

Python, 153 * 0.9 = 137.7 bayt

def p(e):
 for o in"+-*/":
    for i,c in enumerate(e):
        if(c==o)*(0==sum([(d=="(")-(d==")")for d in e[:i]])):return"("+p(e[:i])+o+p(e[i+1:])+")"
 return e

Bu program ondalık girişi yönetir.

İkinci satır boşlukla başlar, ikincisi sekme ile başlar, üçüncüsü iki sekme ile ve üçüncüsü boşlukla başlar. Bu bir bayt kurtardı. İşte bir hexdump ( xxdpp):

0000000: 6465 6620 7028 6529 3a0a 2066 6f72 206f  def p(e):. for o
0000010: 2069 6e22 2b2d 2a2f 223a 0a09 666f 7220   in"+-*/":..for 
0000020: 692c 6320 696e 2065 6e75 6d65 7261 7465  i,c in enumerate
0000030: 2865 293a 0a09 0969 6628 633d 3d6f 292a  (e):...if(c==o)*
0000040: 2830 3d3d 7375 6d28 5b28 643d 3d22 2822  (0==sum([(d=="("
0000050: 292d 2864 3d3d 2229 2229 666f 7220 6420  )-(d==")")for d 
0000060: 696e 2065 5b3a 695d 5d29 293a 7265 7475  in e[:i]])):retu
0000070: 726e 2228 222b 7028 655b 3a69 5d29 2b6f  rn"("+p(e[:i])+o
0000080: 2b70 2865 5b69 2b31 3a5d 292b 2229 220a  +p(e[i+1:])+")".
0000090: 2072 6574 7572 6e20 650a                  return e.

İşte test için kullandığım bir program: (Yukarıdaki programı farklı kaydedin paren.py)

import paren

cases = {
        "2+3*4": "(2+(3*4))", 
        "(2+3)*4": "((2+3)*4)", 
        "1+2+3+4": "(1+(2+(3+4)))", 
        "3/2+5": "((3/2)+5)", 
        "1+2-3": "(1+(2-3))", 
        "2-1+2": "((2-1)+2)",
        "3+-5": "(3+(-5))",
        "1+.12": "(1+.12)",
        "1+0.21/3": "(1+(0.21/3))",
}


for num, case in enumerate(cases):
    print "\n\n\033[1m\033[38;5;14mCase #%d: %s" % (num + 1, case)
    result = paren.p(case)
    print "\033[38;5;4mParenthesize returned: %s" % (result)
    solution = cases[case]
    if result == solution:
        print "\033[38;5;76mCorrect!"
    else:
        print "\033[38;5;9mNot correct!"

Terminalinizin \033[38;5;<COL>mrenkler için çıkış kodunu kullandığından emin olun .


* boşluklu dördüncü?
Element118

1
Bu program geçerli değil prefer to go left-right. OP'de test senaryosu 3'ü deneyin, sonucunuz doğru değil. Bu, örneğin tamsayı aritmetiği ile gerçek bir sorun olabilir ((2*(3/4))+3)(((2*3)/4)+3)
:!

1
@ user12365 Tamsayı aritmetiği kullanılmıyor (örneğin C veya C ++ ile) 3/4 == 0, yani ((2 * (3/4)) + 3) 3 iken (((2 * 3) / 4) + 3) 4
edc65

3

JavaScript (ES6) 179 (263-20% -5% -10%)

(x,W=[],Q=['('],z=1,w=v='',h=p=>'*/+-))('.indexOf(p)|1,C=n=>{for(;h(q=Q.pop())<=h(n);)W[0]=`(${W[1]+q+W.shift()})`;z&&Q.push(q,n)})=>(x+')').replace(/[\d.]+|\S/g,t=>t>'('?t>')'?~h(t)?z?(w+='('+t,v+=')'):C(t,z=1):W=[w+t+v,...W,z=w=v='']:C(t,z=0):z=Q.push(t))&&W[0]

Diğer iki cevap şu anda yanlış olduğundan, benimkini göndereceğim. Burada ve burada ve başka bir yerde kullandığım ifade ayrıştırıcısının bir varyasyonu . Daha ayrıntılı algoritma açıklamaları için oraya bakın.

Oldukça hantal ama işe yaramalı.

Test snippet'i

f=(x,W=[],Q=['('],z=1,w=v='',h=p=>'*/+-))('.indexOf(p)|1,C=n=>{for(;h(q=Q.pop())<=h(n);)W[0]=`(${W[1]+q+W.shift()})`;z&&Q.push(q,n)})=>(x+')').replace(/[\d.]+|\S/g,t=>t>'('?t>')'?~h(t)?z?(w+='('+t,v+=')'):C(t,z=1):W=[w+t+v,...W,z=w=v='']:C(t,z=0):z=Q.push(t))&&W[0]

// More readable
x=(x,W=[],Q=['('],z=1,w=v='',
  h=p=>'*/+-))('.indexOf(p)|1,
  C=n=>{
    for(;h(q=Q.pop())<=h(n);)W[0]=`(${W[1]+q+W.shift()})`;
    z&&Q.push(q,n)
  }
)=>(
  (x+')')
  .replace(/[\d.]+|\S/g,t=> 
       t>'('    
       ?t>')'
       ?~h(t)
       ?z
       ?(w+='('+t,v+=')')
       :C(t,z=1)
       :W=[w+t+v,...W,z=w=v=''] // overfill W to save 2 chars ()
       :C(t,z=0)
       :z=Q.push(t)
  ),
  W[0]
)

console.log=(...x)=>O.textContent+=x.join` `+'\n'

// TEST
;[
  ['1+2*3','(1+(2*3))'],['2*(3+4)','(2*(3+4))'],['2*3/4+3','(((2*3)/4)+3)'],['342*32/8','((342*32)/8)'],
  ['3+-5','(3+(-5))'],['-3+-4*7','((-3)+((-4)*7))'], // bonus 20%
  ['3  + 4','(3+4)'], // bonus 5%
  ['1+.12','(1+.12)'],['1+0.21/3','(1+(0.21/3))'] // bonus 10%
].forEach(t=>{var k=t[1],i=t[0],r=f(i); console.log(i+' : '+r+(r==k? ' OK':' Fail expecting '+k))})
<pre id=O></pre>


1

Python, 241 * 0.8 * 0.95 * 0.9 = 164.84 karakter

Kullandığım ast (Özet sözdizimi Ağaçları) kütüphane ve homebrew string değiştirme dicti. Dize değiştirme çok pahalı, ancak bonus skoru biraz düşük tutmaya yardımcı oluyor. Belki (ip değiştirme parçası) daha fazla golf olabilir.

Bu çözümün her sayıya fazladan bir parantez eklediğini unutmayın, ancak bunun sorunun ruhu içinde olduğunu düşünüyorum

import ast;def p(e):
 r,s={"Module([":"",")])":"","Expr(":"","BinOp":"","Num":"",", Add(), ":"+",", Sub(), ":"-",", Div(), ":"/",", Mult(), ":"*"},ast.dump(ast.parse(e),annotate_fields=False)
 for f,t in r.iteritems():s=s.replace(f,t)
 return s

Test odası:

cases = {
    "2+3*4", 
    "(2+3)*4", 
    "1+2+3+4", 
    "3/2+5", 
    "1+2-3", 
    "2-1+2",
    "3+-5",
    "1+.12",
    "1+0.21/3"
}

for num,case in enumerate(cases):
    result = p(case)
    print "Case {}: {:<16} evaluates to: {}".format(num+1,case,result)

Test takımının çıktısı:

Case 1: 3+-5             evaluates to: ((3)+(-5))
Case 2: 3/2+5            evaluates to: (((3)/(2))+(5))
Case 3: 2+3*4            evaluates to: ((2)+((3)*(4)))
Case 4: 1+2+3+4          evaluates to: ((((1)+(2))+(3))+(4))
Case 5: 1+0.21/3         evaluates to: ((1)+((0.21)/(3)))
Case 6: (2+3)*4          evaluates to: (((2)+(3))*(4))
Case 7: 2-1+2            evaluates to: (((2)-(1))+(2))
Case 8: 1+.12            evaluates to: ((1)+(0.12))
Case 9: 1+2-3            evaluates to: (((1)+(2))-(3))

Eksik import astkod içinde
edc65

Ve bu yüzde bonusu ödemenin doğru yolu değil. % 50 indirim ve% 50 daha yüksek bir indirim alırsanız, 0 ödemezsiniz. Puanınız 157.32 olmalıdır (ithalat satırını ekledikten sonra bir şey daha). Bu iyi bir puan - Düzeltme
yaparsanız oylayacağım

İyi bir nokta. İçe aktarma eklendi. Şimdi 241 karakter. Bonusu nasıl hesaplayacağınızdan emin değilim.
Yorumunuzu

Bonus çıkarılmaz (bu bir çarpmadır) ve düzen önemli değildir. 241 * (% 1-20) * (% 1-5) * (% 1-10) => 241 * 0.8 * 0.95 * 0.9 => 164.84
edc65

@ edc65 Ah. Sağ. Düz düşünmüyordum. Teşekkürler.
agtoever
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.