불필요한 괄호 제거


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 .

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

코드는 다음과 같습니다.

{`<((\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.