给表达式加上括号


20

最近,我一直在写一种新的语言,以避免需要处理操作的顺序,我只是对每个表达式加上括号以完全避免这种情况。

因为括号位于字符代码40-41,所以您的代码将需要尽可能短。


例子

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)

规则

您需要处理的唯一操作是:(*乘法),/(除法),+(加法)和-(减法)。

  • 操作的顺序是:
    • 插入语
    • 乘法,除法
    • 加法,减法
  • 您应该宁可左右走
  • 输入数字将始终为正整数(请参阅奖励)

奖金

如果处理否定,则为-20%

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

-5%(如果您允许在输入内部放置空格):

3  + 4
(3+4)

如果您可以在输入中处理小数,则为-10%

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

500赏金:如果您设法以“ 未命名 / 块”形式填写答案


25
“因为括号位于字符代码40-41,所以您的代码必须尽可能短。” 好吧,现在您只是简直荒谬。; P
ETHproductions 2015年

3
这比前缀(波兰语)表示法还容易,因为?
wizzwizz4 2015年

3
可能重复
瑕疵的

8
@flawr我看到了,但事实是这个问题让您输出了用括号括起表达式的所有方式,这是非常不同的。在这里,您必须考虑到操作顺序,我认为这是一个很大的不同,因为无法轻松地对此挑战进行代码修改
Downgoat 2015年

3
重要的测试案例:(1+2+3+4某些解决方案可能用括号括起来((1+2)+(3+4))
Martin Ender

Answers:


2

Python,153 * 0.9 = 137.7字节

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

该程序处理十进制输入。

第二行以空格开头,第二行以标签开头,第三行以两个标签开头,第三行以空格开头。这样节省了一个字节。这是一个十六进制转储(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.

这是我用于测试的程序:(将程序另存为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!"

确保您的终端\033[38;5;<COL>m对颜色使用转义码。


*第四个空格?
Element118

1
这个程序没有prefer to go left-right。在OP中尝试测试用例3,结果不正确。例如使用整数算术,这可能是一个实际问题:((2*(3/4))+3)!=(((2*3)/4)+3)
edc65

1
@ user12365不使用整数算术(例如在C或C ++中)3/4 == 0,所以(((2 *(3/4))+ 3)为3,而(((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]

由于其他两个答案目前都错了,我将发布我的答案。这是我在这里使用的表达式解析器的一种变体这里和其他地方。在此处查找更详细的算法说明。

它相当笨重,但应该可以使用。

测试片段

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个字符

我正在使用ast(抽象语法树)库和自制字符串替换字典。更换琴弦会花费很多,但奖金有助于将分数保持在较低水平。也许(琴弦更换部件)可以打更多的高尔夫球。

请注意,此解决方案在每个数字周围添加了一组额外的括号,但我认为这属于问题的精神

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

测试套件:

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)

测试套件的输出:

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

import ast您的代码缺失
edc65

那不是获得百分比奖金的正确方法。如果您获得50%的折扣,然后再享受50%的折扣,则您无需支付0。您的分数应为157.32(添加进口行后的价格还要高一些)。那是一个很好的成绩-如果您解决问题,我会
投票

好点子。添加了导入。现在有241个字符。虽然不确定如何计算奖金。如果我正确理解您的评论,那么奖金的扣除顺序
就很

奖金不减去(它是一个乘法),顺序无关紧要。241 *(1-20%)*(1-5%)*(1-10%)=> 241 * 0.8 * 0.95 * 0.9 => 164.84
edc65

@ edc65啊。对。没想清楚。谢谢。
agtoever
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.