Dấu ngoặc đơn


20

Gần đây tôi đã viết một ngôn ngữ mới , để tránh phải xử lý thứ tự các thao tác , tôi chỉ đơn giản là ngoặc đơn cho từng biểu thức để tránh hoàn toàn điều này.

Vì dấu ngoặc đơn ở mã char 40-41, mã của bạn sẽ cần phải càng ngắn càng tốt.


Ví dụ

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)

Quy tắc

Các thao tác duy nhất bạn cần xử lý là: *(nhân), /(chia), +(cộng) và -(trừ).

  • Thứ tự của các hoạt động là:
    • Dấu ngoặc
    • Nhân, chia
    • Chấm, trừ
  • Bạn nên đi bên trái
  • Các số đầu vào sẽ luôn là số nguyên dương (xem phần thưởng)

Tiền thưởng

-20% nếu bạn xử lý phủ định:

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

-5% nếu bạn cho phép không gian được đặt bên trong đầu vào:

3  + 4
(3+4)

-10% nếu bạn có thể xử lý số thập phân trong đầu vào:

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

500 tiền thưởng: nếu bạn quản lý để viết câu trả lời trong Chưa đặt tên / Khối


25
"Bởi vì dấu ngoặc đơn nằm ở mã char 40-41, mã của bạn sẽ cần phải càng ngắn càng tốt." OK, bây giờ bạn chỉ đơn giản là vô lý. ; P
Sản phẩm ETH

3
Và điều này dễ hơn ký hiệu tiền tố (Ba Lan) bởi vì?
wizzwizz4

3
Có thể trùng lặp .
flawr

8
@flawr Tôi đã thấy điều đó nhưng nó rất khác trong thực tế rằng câu hỏi đó đã đưa ra tất cả các cách làm ngoặc đơn cho một biểu thức. Ở đây bạn phải tính đến thứ tự các hoạt động mà tôi nghĩ là một sự khác biệt đáng kể vì mã không thể được sửa đổi một cách tầm thường cho thách thức này
Downgoat

3
Trường hợp thử nghiệm quan trọng: 1+2+3+4(mà một số giải pháp nhất định có thể là dấu ngoặc đơn ((1+2)+(3+4)))
Martin Ender

Câu trả lời:


2

Python, 153 * 0.9 = 137.7 byte

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

Chương trình này xử lý đầu vào thập phân.

Dòng thứ hai bắt đầu bằng một khoảng trắng, dòng thứ hai bắt đầu bằng một tab, dòng thứ ba có hai tab và dòng thứ ba có khoảng trắng. Điều này đã lưu một byte. Đây là một 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.

Đây là chương trình tôi đã sử dụng để thử nghiệm: (Lưu chương trình ở trên dưới dạng 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!"

Hãy chắc chắn rằng thiết bị đầu cuối của bạn sử dụng \033[38;5;<COL>mmã thoát cho màu sắc.


* thứ tư với một không gian?
Element118

1
Chương trình này không có prefer to go left-right. Hãy thử trường hợp thử nghiệm 3 trong OP, kết quả của bạn không chính xác. Đây có thể là một vấn đề thực sự, ví dụ với số học số nguyên : ((2*(3/4))+3)! =(((2*3)/4)+3)
edc65

1
@ user12365 Không sử dụng số học số nguyên (ví dụ như trong C hoặc C ++) 3/4 == 0, vì vậy ((2 * (3/4)) + 3) là 3, trong khi (((2 * 3) / 4) + 3) là 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]

Vì hai câu trả lời khác hiện tại đều sai, tôi sẽ đăng của tôi. Đó là một biến thể của trình phân tích cú pháp biểu thức mà tôi đã sử dụng ở đâyở đây và ở một nơi khác. Nhìn vào đó để giải thích thuật toán chi tiết hơn.

Nó khá cồng kềnh nhưng nó sẽ hoạt động.

Kiểm tra đoạn

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 ký tự

Tôi đang sử dụng thư viện ast (Tóm tắt Cú pháp Cây) và một lệnh thay thế chuỗi homebrew. Việc thay thế chuỗi tốn kém rất nhiều, nhưng phần thưởng giúp duy trì điểm số hơi thấp. Có lẽ (phần thay thế chuỗi) có thể được chơi golf hơn nữa.

Lưu ý rằng giải pháp này bổ sung thêm một bộ dấu ngoặc đơn xung quanh mỗi số, nhưng tôi nghĩ đó là trong tinh thần của câu hỏi

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

Bộ kiểm tra:

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)

Đầu ra của bộ thử nghiệm:

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

Thiếu import astmã của bạn
edc65

Và đó không phải là cách đúng để hoàn trả phần trăm tiền thưởng. Nếu bạn được giảm giá 50% và trên 50% khác, bạn không phải trả 0. Điểm của bạn sẽ là 157,32 (một số thứ nữa sau khi thêm dòng nhập). Đó là một điểm số tốt - Tôi sẽ nâng cao nếu bạn khắc phục
edc65

Điểm tốt. Đã thêm nhập. Bây giờ có 240 ký tự. Không chắc chắn làm thế nào để tính tiền thưởng mặc dù. Nếu tôi hiểu nhận xét của bạn một cách chính xác, thứ tự mà phần thưởng bị trừ đi là vấn đề ...
bất cứ lúc nào

Phần thưởng không bị trừ (đó là một số nhân) và thứ tự không quan trọng. 241 * (1-20%) * (1-5%) * (1-10%) => 241 * 0.8 * 0.95 * 0.9 => 164.84
edc65

@ edc65 À. Đúng. Không suy nghĩ thẳng. Cảm ơn.
bất cứ lúc nào
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.