불필요한 괄호 제거


32

문자로 구성된 문자열이 제공 0123456789+*()됩니다. 문자열이 항상 유효한 수학식이라고 가정 할 수 있습니다.

곱셈이 덧셈보다 우선 순위가 높다고 가정하면 불필요한 괄호를 제거해야합니다.

괄호는 구조적으로 필요하지 않은 경우에만 제거해야합니다 .

  • 곱셈 우선 순위가 높기 때문에 3+(4*5)=>3+4*5
  • 곱셈 또는 덧셈 연관성으로 인해 : 3*(4*5)=>3*4*5
  • 표현식 주위에 중복되는 경우 : 3*((4+5))=>3*(4+5)

특정 숫자 값으로 인해 괄호 를 단순화 할 수있는 경우 괄호 를 유지해야 합니다.

  • 1*(2+3) 단순화해서는 안된다 1*2+3
  • 0*(1+0) 단순화해서는 안된다 0*1+0

예 :

(4*12)+11         ==>    4*12+11
(1+2)*3           ==>    (1+2)*3
3*(4*5)           ==>    3*4*5
((((523))))       ==>    523
(1+1)             ==>    1+1
1*(2*(3+4)*5)*6   ==>    1*2*(3+4)*5*6
1*(2+3)           ==>    1*(2+3)
0*(1+0)           ==>    0*(1+0)


(((2+92+82)*46*70*(24*62)+(94+25))+6)    ==>    (2+92+82)*46*70*24*62+94+25+6

1
더 많은 테스트 사례가 있습니까?
— Leaky Nun

2
1*(2*(3+4)*5)*6흥미로운 테스트 사례이어야합니다 (현재 솔루션에 실패했습니다).
— Leaky Nun

8
"불필요한"은 구조적으로 또는 사례별로 정의됩니까? 다시 말해, 괄호는 여기서 불필요합니까? (2+2)*1
— Luis Mendo

2
@LuisMendo 나는 그것의 공정한 어느 방법으로 그것을 해석하는 생각
— anatolyg

2
@anatolyg 두 가지에 대한 접근 방식이 매우 다르기 때문에 그것이 공정하지 않다고 생각합니다. 우리가 약간의 설명을 얻는다면 좋을 것입니다.
— Sp3000

답변:


15

매스 매 티카, 105 97 91 바이트

Roman 덕분에 -6 바이트 !

a=StringReplace;ToString@ToExpression@a[#,{"*"->"**","+"->"~~"}]~a~{" ** "->"*","~~"->"+"}&

대체합니다 +및 *과 ~~( StringExpression)와 **( NonCommutativeMultiply)는 각각 stringifies에게 그것을 그것을 평가하고, 다시 연산자를 대체합니다.


뭐? Mathematica는 내장되어 있지 않습니까?
— 아웃 골퍼 Erik

@EriktheGolfer 그것은 기본적으로 않습니다; 연산자를 평가 하지 않도록 노력하고 있습니다.
— LegionMammal978

그것이 바로 Mathematica가 광고와 비용이 많이 드는 이유입니다. 그러나 Mathematica는 퍼즐이 충분히 어렵다면 다른 언어로 바뀌지 않았지만 "다른 언어"는 전혀 경쟁하지 않습니다.
— Outgolfer Erik

StringExpression대신에 를 사용 Dot하고 " "->""절을 제거 하여 91 바이트 :a=StringReplace;ToString@ToExpression@a[#,{"*"->"**","+"->"~~"}]~a~{" ** "->"*","~~"->"+"}&
— Roman

@Roman 감사합니다! 숫자와 결합하지 않는 또 다른 좋은 비 회계 비평가 비평가 연산자를 발견 한 것 같습니다.
— LegionMammal978

7

자바 스크립트 (ES6) 163 178

15 바이트 저장된 @IsmaelMiguel 편집

a=>eval(`s=[]${_=';for(b=0;a!=b;a=b.replace(/'}\\(([^()]*)\\)(?=(.?))/,(x,y,z,p)=>~y.indexOf('+')?-s.push(b[p-1]=='*'|z=='*'?x:y):y))b=a;${_}-\\d+/,x=>s[~x]))b=a`)

덜 골프

a=>{
  for(s=[],b='';
      a!=b;
      a=b.replace(/\(([^()]*)\)(?=(.?))/,(x,y,z,p)=>y.indexOf('+')<0?y:-s.push(b[p-1]=='*'|z=='*'?x:y)))
    b=a;
  for(b=0;
      a!=b;
      a=b.replace(/-\d+/,x=>s[~x]))
    b=a;
  return a
}

테스트

f=a=>eval(`s=[]${_=';for(b=0;a!=b;a=b.replace(/'}\\(([^()]*)\\)(?=(.?))/,(x,y,z,p)=>~y.indexOf('+')
?-s.push(b[p-1]=='*'|z=='*'?x:y)
:y))b=a;${_}-\\d+/,x=>s[~x]))b=a`)

console.log=x=>O.textContent+=x+'\n'

test=`(4*12)+11         ==>    4*12+11
(1+2)*3           ==>    (1+2)*3
3*(4*5)           ==>    3*4*5
((((523))))       ==>    523
(1+1)             ==>    1+1
1*(2*(3+4)*5)*6   ==>    1*2*(3+4)*5*6
1*(2+3)           ==>    1*(2+3)
0*(1+0)           ==>    0*(1+0)
(((2+92+82)*46*70*(24*62)+(94+25))+6)    ==>    (2+92+82)*46*70*24*62+94+25+6`

test.split`\n`.forEach(r=>{
  var t,k,x
  [t,,k]=r.match(/\S+/g)
  x=f(t)
  console.log((x==k?'OK ':'KO ')+t+' -> '+x+(x==k?'':' expected '+k))
})
<pre id=O></pre>


왜 y.indexOf('+')대신에 쓰셨 y.indexOf`+`[...]습니까? ([...] 형식이 트립되지 않도록 추가되었습니다.) 그런 식으로 버그가 발생 했습니까?
— Ismael Miguel

1
여기에 170 바이트가 있습니다 :a=>eval(`for(b=s=[]${_=';a!=b;a=b.replace(/'}\\(([^()]*)\\)(?=(.?))/,(x,y,z,p)=>~y.indexOf('+')<0?-s.push(b[p-1]=='*'|z=='*'?x:y):y))b=a;for(b=0${_}-\\d+/,x=>s[~x]))b=a`)
— Ismael Miguel

@IsmaelMiguel 정말 영리합니다, 감사합니다! 교훈 : 평가로
— 넘어갈

코드를 줄이는 간단한 솔루션이 마음에 들었습니다. 난에 대해 뭔가 할 수 있으면 좋겠다 for(b=, =='*'및 기타 반복 비트. 또한 ~y.indexOf('+')<0같지 ~y.indexOf('+')않습니까? 유일한 값 때문에 그게 indexOf()falsy 값으로 평가가 반환 -1의는 <0중복 보인다. 또는 내가 틀렸다면 당신은 할 수 있습니다y.indexOf('+')>1
— Ismael Miguel

@IsmaelMiguel 1 : 예, <0골 판이없는 버전에 남아있는 쓰레기이므로 제거해야합니다. 2 : 다시 생각 for하면 반복 부분에 포함되도록 수정 될 수 있습니다. 다시 한번 감사드립니다
— edc65

5

Python에서 Python3 + PEG 구현 , 271 바이트

import peg
e=lambda o,m=0:o.choice and str(o)or(m and o[1][1]and"("+e(o[1])+")"or e(o[1]))if hasattr(o,"choice")else o[1]and e(o[0],1)+"".join(str(x[0])+e(x[1],1)for x in o[1])or e(o[0])
print(e(peg.compile_grammar('e=f("+"f)*f=p("*"p)*p="("e")"/[0-9]+').parse(input())))

얼마 전에 파이썬에서 PEG 구현을 만들었습니다 . 나는 그것을 여기서 사용할 수 있다고 생각합니다.

식을 트리로 구문 분석하고 자식이 추가되고 부모가 곱셈 인 경우에만 괄호를 유지합니다.


4

펄, 132 바이트

-p플래그의 경우 129 바이트 소스 + 3 :

#!perl -p
0while s!\(([^\(\)]+)\)!$f{++$i}=$1,"_$i"!e;s!_$i!($v=$f{$i})=~/[+]/&&($l.$r)=~/[*]/?"($v)":$v!e
while($l,$i,$r)=/(.?)_(\d+)(.?)/

사용 :

echo "1*(2*(3+4)*5)*6" | perl script.pl

4

루비, 140130 바이트

-p플래그의 경우 127 바이트 소스 + 3 :

t={}
r=?%
0while$_.gsub!(/\(([^()]+)\)/){t[r+=r]=$1;r}
0while$_.gsub!(/%+/){|m|(s=t[m])[?+]&&($'[0]==?*||$`[/\*$/])??(+s+?):s}

그리고 ungolfed :

tokens = Hash.new
key = '%'

# convert tokens to token keys in the original string, innermost first
0 while $_.gsub!(/\(([^()]+)\)/) { # find the innermost parenthetical
  key += key # make a unique key for this token
  tokens[key] = $1
  key # replace the parenthetical with the token key in the original string
}

# uncomment to see what's going on here
# require 'pp'
# pp $_
# pp tokens

# convert token keys back to tokens, outermost first
0 while $_.gsub!(/%+/) {|key|
  str = tokens[key]
  if str['+'] and ($'[0]=='*' or $`[/\*$/]) # test if token needs parens
    '(' + str + ')'
  else
    str
  end
}
# -p flag implicity prints $_

아주 좋은 답변입니다. 무엇이 일어나고있다 0 while구문?
— 요나

1
@Jonah Ruby에서는 expr while cond에 해당합니다 while cond; expr; end. 여기서는 cond반복적으로 만 수행 하고 실제로 루프 본문이 없습니다. 일반적으로 하나 같이이 쓰기 것 while cond; end혹은 loop{ break unless cond }하지만 0 while cond적은 바이트입니다. 는 0아무것도하지 않는다; while 루프의 짧은 형식에는 본문이 필요하기 때문에 바로 거기에 있습니다.
— ezrast

2

레티 나, 155 바이트

{`\(((\d+|\((((\()|(?<-5>\))|[^()])*(?(5)^))\))(\*(\d+|\((((\()|(?<-10>\))|[^()])*(?(10)^))\)))*)\)
$1
(?<!\*)\((((\()|(?<-3>\))|[^()])*(?(3)^))\)(?!\*)
$1

온라인으로 사용해보십시오!

모든 테스트 케이스를 한 번에 확인하십시오.

설명

가장 중요한 것은이 코드입니다.

(((\()|(?<-3>\))|[^()])*(?(3)^)

이 정규식은 대괄호가 균형을 이루는 문자열 (예 : 1+(2+(3))+4또는) 과 일치 할 수 있습니다 2+3.

설명의 편의를 위해이 정규식을 B .

또한, 우리가 사용할 수 있도록 <하고 >대신 브라켓뿐만 아니라 대한 p및 m에 \+와 \*.

코드는 다음과 같습니다.

{`<((\d+|<B>)(m(\d+|<B>))*)>
$1
(?<!m)<B>(?!m)
$1

처음 두 줄은 곱하기만으로 구성되는 괄호 (예 : (1*2*3)또는 짝수) 와 일치합니다 (1*(2+3)*4). 그것들은 내부의 내용으로 대체됩니다.

마지막 두 줄은 앞에 오지 않고 곱하기 뒤에 괄호와 일치합니다. 그것들은 내부의 내용으로 대체됩니다.

초기 {`는 "등 전성이 될 때까지 교체"를 의미합니다. 즉, 교체는 더 이상 일치하지 않거나 스스로 교체 될 때까지 완료됩니다.

이 경우 교체는 더 이상 일치하지 않을 때까지 수행됩니다.


에 실패합니다 1*(2*(3+4)*5)*6.
— orlp

@orlp 감사합니다.
— Leaky Nun

실패(1*(2+3)+4)*5
— Sp3000

@ Sp3000 감사합니다.
— Leaky Nun

2

파이썬 3, 274 269 359 337 336 바이트

이 방법은 기본적으로 가능한 모든 괄호 쌍을 제거하고 여전히 동일한 지 평가하는지 확인합니다.

from re import *
def f(x):
    *n,=sub('\D','',x);x=sub('\d','9',x);v,i,r,l=eval(x),0,lambda d,a,s:d.replace(s,"?",a).replace(s,"",1).replace("?",s),lambda:len(findall('\(',x))
    while i<l():
        j=0
        while j<l():
            h=r(r(x,i,"("),j,")")
            try:
                if eval(h)==v:i=j=-1;x=h;break
            except:0
            j+=1
        i+=1
    return sub('9','%s',x)%tuple(n)

테스트 하니스

print(f("(4*12)+11")=="4*12+11")
print(f("(1+2)*3") =="(1+2)*3")
print(f("3*(4*5)")=="3*4*5")
print(f("((((523))))")=="523")
print(f("(1+1)")=="1+1")
print(f("1*(2*(3+4)*5)*6")=="1*2*(3+4)*5*6")
print(f("(((2+92+82)*46*70*(24*62)+(94+25))+6)")=="(2+92+82)*46*70*24*62+94+25+6")
print(f("1*(2+3)")=="1*(2+3)")
print(f("0*(1+0)")=="0*(1+0)")

업데이트

  • -1 [16-10-04] 추가 공간 제거
  • -22 [16-05-07] relib를 사용함
  • +90 [16-05-07] 새로운 테스트 케이스를 처리하도록 업데이트되었습니다
  • -5 [16-05-07] 길이 ( l) 람다 에서 제거 된 매개 변수

1
1*(2+3)OP가 특수한 경우를 단순화하지 않기로 결정했기 때문에 테스트 사례가 실패합니다 . 좋은 대답이지만; 이것은 나의 공감대가 있습니다.
— HyperNeutrino

1
@AlexL. 그것을 잡아 주셔서 감사합니다! 테스트 사례 D를 업데이트하지 않았습니다. D :하지만 이제 수정되었습니다.
— NonlinearFruit

1

PHP, 358 바이트

function a($a){static$c=[];$d=count($c);while($g=strpos($a,')',$g)){$f=$a;$e=0;for($j=$g;$j;--$j){switch($a[$j]){case')':++$e;break;case'(':--$e;if(!$e)break 2;}}$f[$g++]=$f[$j]=' ';if(eval("return $f;")==eval("return $a;"))$c[str_replace(' ', '', $f)]=1;}if(count($c)>$d){foreach($c as$k=>$v){a($k);}}return$c;}$t=a($argv[1]);krsort($t);echo key($t);

인상적인 길이는 아니지만, 최적이 아닌 접근 방식을 사용하고 최적의 언어를 사용하지 않으면 얻을 수 있습니다.

한 쌍의 괄호를 제거하고 결과 표현식을 회피합니다. 결과가 원본과 동일하면 결과를 유효한 표현식의 맵에 추가하고 새 표현식을 찾을 수 없을 때까지 반복됩니다. 그런 다음 가장 짧은 유효한 표현식을 인쇄합니다.

표현식의 결과가 커지고 중단 / 지수 표기법으로 캐스트 될 때 중단됩니다.


1

프롤로그 (SWI) , 122 (118) 바이트

T+S:-term_string(T,S).
I/O:-X+I,X-Y,Y+O.
E-O:-E=A+(B+C),A+B+C-O;E=A*(B*C),A*B*C-O;E=..[P,A,B],A-X,B-Y,O=..[P,X,Y];E=O.

온라인으로 사용해보십시오!

//2첫 번째 인수의 문자열 값에서 괄호를 제거하고 두 번째 인수를 통해 문자열을 출력 하는 술어 를 정의합니다 . 입력이 프롤로그 용어 일 수있는 경우 이는 81 일뿐입니다.+/2 verbose를 처리하지 않고 정의하는 77 바이트 term_string/2일 뿐이지 만 불필요한 괄호는 그 방법으로 시작하기 위해 존재하지 않았기 때문에 부정 행위에 가깝습니다. 모든 +/2수행은 핸들의 연관성이다.

나는 =../2그것을 모두 사용하려고했지만 목록으로 작업하는 3 바이트 연산자가 정확히 간결하지 않기 때문에 훨씬 길어졌습니다.

프롤로그 (SWI) 124 바이트

T+S:-term_string(T,S).
I/O:-X+I,X-Y,Y+O.
X-Y:-X=..[O,A,B],(B=..[O,C,D],E=..[O,A,C],F=..[O,E,D],F-Y;A-C,B-D,Y=..[O,C,D]);X=Y.

온라인으로 사용해보십시오!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.