不要な括弧を削除する


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
もっとテストケースをお願いします?
リーキー修道女

2
1*(2*(3+4)*5)*6興味深いテストケースである必要があります(私のソリューションでは現在失敗しています)。
漏れの修道女

8
「不要」は構造的に定義されていますか、それともケースごとに定義されていますか?つまり、ここで括弧は不要ですか?(2+2)*1
ルイスメンドー

2
@LuisMendoいずれかの方法で解釈するのは公平だと思う
アナトリグ

2
@anatolyg 2つのアプローチは非常に異なるため、これは公平だとは思いません。何らかの説明があればいいでしょう。
Sp3000

回答:


15

Mathematica、105 97 91バイト

ローマンのおかげで-6バイト!

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

+*をそれぞれ~~StringExpression)と**NonCommutativeMultiply)で置き換え、評価し、文字列化し、演算子を元に戻します。


何?Mathematicaには組み込み機能がありませんか?
エリックアウトゴルファー

@EriktheGolfer基本的にはそうです。演算子を評価しないようにしてます。
LegionMammal978

だからこそ、Mathematicaはとても宣伝されており、とても高価だ...私が考えている組み込み機能のために。しかし、パズルが十分に難しい場合、Mathematicaは他の言語に変更を加えていませんが、「他の言語」はここではまったく競争していません。
エリックアウトゴルファー

StringExpression代わりにを使用Dotし、" "->""句を削除して91バイトa=StringReplace;ToString@ToExpression@a[#,{"*"->"**","+"->"~~"}]~a~{" ** "->"*","~~"->"+"}&
ローマン

@Romanありがとう!数値と結合しない、別の適切な非交換性の未評価の演算子を見つけたようです。
LegionMammal978

7

JavaScript(ES6)163 178

@IsmaelMiguelに保存された15バイトの編集

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`+`[...]ですか?([...]書式設定のトリップを回避するために追加されました)そのようにバグがありましたか?
イスマエルミゲル

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`)
イスマエルミゲル

@IsmaelMiguelそれは本当に賢いです、ありがとう!レッスンは学んだ:evalに渡すときに、すべて再びそれを再考する
edc65

あなたのコードを減らすための私のシンプルなソリューションが気に入ってくれてうれしいです。for(b==='*'および他の繰り返される部分について何かできるといいのですが。また、と~y.indexOf('+')<0同じではありません~y.indexOf('+')か?indexOf()偽の値に評価される戻り値はのみであるため、は冗長-1<0ようです。または、私がそれを間違えた場合、あなたはすることができますy.indexOf('+')>1
イスマエルミゲル

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

しばらく前に、PythonでPEG実装を作成しました。ここで使用できると思います。

式をツリーに解析し、子が加算で、親が乗算の場合にのみ括弧を保持します。


4

Perl、132バイト

129バイトのソース+ -pフラグ用の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バイト

127バイトのソース+ -pフラグ用の3 :

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

そして、無制限:

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ループの短い形式にはbodyが必要なため、そこにあります。
ezrast

2

網膜、155バイト

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

オンラインでお試しください!

すべてのテストケースを一度に検証します。

説明

主なものはこのコードです:

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

この正規表現は、例えば、括弧がバランスされている任意の文字列を一致させることができます1+(2+(3))+42+3

説明を簡単にするために、この正規表現をとしますB

また、私たちが使ってみましょう<>だけでなく、ブラケットのための代わりpmするために\+\*

コードは次のようになります。

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

最初の2行は、乗算だけで構成されるブラケット(例:(1*2*3)または)に一致します(1*(2+3)*4)。それらは内部のコンテンツに置き換えられます。

最後の2行は、前になく、乗算の後にない括弧に一致します。それらは内部のコンテンツに置き換えられます。

最初{`は「べき等になるまで置換する」ことを意味します。つまり、置換は、一致しなくなるか、自分で置換されるまで行われます。

この場合、置換は一致しなくなるまで行われます。


失敗し1*(2*(3+4)*5)*6ます。
-orlp

@orlpありがとう、修正。
漏れの修道女

失敗(1*(2+3)+4)*5
Sp3000

@ Sp3000ありがとう、修正。
漏れの修道女

2

Python 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は、特別な番号のケースでは単純化しないと述べているため、これはテストケースに失敗します。ただし、良い答えです。これには私の賛成票があります。
ハイパーニュートリノ

1
@AlexL。キャッチしてくれてありがとう!テストケースを更新しませんでした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最初の引数の文字列値から括弧を削除し、2番目の引数を介して文字列を出力する述語を定義します。入力がPrologの用語である場合、これはverboseを処理せずに定義する81 77バイトのみになりますが、多くの不必要な括弧はその方法で始まるために存在しないため、不正行為にかなり近いでしょう。その全て行い、ハンドル結合性です。+/2term_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.