3
$\begingroup$

I have arithmetic expressions given as strings with excessive parentheses, and I want to convert them into symbolic Mathematica expressions that retain their structure but are formatted with only the necessary parentheses—i.e., redundant parentheses that don’t affect operator precedence or associativity should be removed. For example, I want the following transformations:

"(((((((1*2)-3)+4)+5)+6)-7)+8)+9" -> "1*2-3+4+5+6-7+8+9" "(((((((1*2)+3)-4)+5)/6)*7)+8)+9" -> "(1*2+3-4+5)/6*7+8+9" "(((1+2)-((3*4)*5))+(6*(7+8)))-9" -> "1+2-3*4*5+6*(7+8)-9" 

I tried using ToExpression with Hold to prevent evaluation:

ToExpression["(((((((1*2)-3)+4)+5)+6)-7)+8)+9", InputForm, Hold] 

This correctly avoids numerical evaluation, but the resulting expression still reflects the original parenthesization.

$\endgroup$

2 Answers 2

4
$\begingroup$
parse[expr_String] := Module[{foo, bar, res}, foo // Attributes = Flat; bar // Attributes = Flat; expr // MakeExpression // ReplaceAll[{Plus -> foo, Times -> bar}] // ReleaseHold // Evaluate // Defer // ReplaceAll[{foo -> Plus, bar -> Times}] ] s1 = "(((((((1*2)-3)+4)+5)+6)-7)+8)+9"; s2 = "(((((((1*2)+3)-4)+5)/6)*7)+8)+9"; s3 = "(((1+2)-((3*4)*5))+(6*(7+8)))-9"; parse /@ {s1, s2, s3} 
{ 1 2 - 3 + 4 + 5 + 6 - 7 + 8 + 9, 1/6 (1 2 + 3 - 4 + 5) 7 + 8 + 9, 1 + 2 - 3 4 5 + 6 (7 + 8) - 9 } 
$\endgroup$
2
  • 1
    $\begingroup$ But the output is not a string. But maybe OP is OK with it. $\endgroup$ Commented Oct 1 at 20:07
  • 3
    $\begingroup$ I was just going to flatten out plus and times manually: ToExpression[string, InputForm, Inactivate] /. op : Inactive[Plus|Times] :> Flatten@*op // HoldForm[#] & // Activate $\endgroup$ Commented Oct 1 at 21:51
3
$\begingroup$

New better version:

It uses my algorithm in Update section of my question here.

It checks whether removing particular pair of parentheses changes value of expression, if not then the pair of parenthesis is removed.

fu[s_] := Module[{ps = Flatten[StringPosition[s, #] & /@ StringCases[s, "(" ~~ Shortest[x___] ~~ ")" /; StringCount[x, "("] == StringCount[x, ")"], Infinity, Overlaps -> True], 1], sps}, sps = Select[ps, ToExpression@ StringReplacePart[s, "", {{#[[1]], #[[1]]}, {#[[2]], #[[2]]}}] == ToExpression[s] &]; StringReplacePart[s, "", Flatten[{{#[[1]], #[[1]]}, {#[[2]], #[[2]]}} & /@ sps, 1]] ] s1 = "(((((((1*2)-3)+4)+5)+6)-7)+8)+9"; s2 = "(((((((1*2)+3)-4)+5)/6)*7)+8)+9"; s3 = "(((1+2)-((3*4)*5))+(6*(7+8)))-9"; fu /@ {s1, s2, s3} 

{"1*2-3+4+5+6-7+8+9", "(1*2+3-4+5)/6*7+8+9", "1+2-3*4*5+6*(7+8)-9"} 

Old version:

This works for the three examples (although the second example can have one less parenthesis but OP has the same one redundant parenthesis):

s1 = "(((((((1*2)-3)+4)+5)+6)-7)+8)+9"; s2 = "(((((((1*2)+3)-4)+5)/6)*7)+8)+9"; s3 = "(((1+2)-((3*4)*5))+(6*(7+8)))-9"; (Hold[ToExpression[s1, InputForm, Hold] /. x_Integer :> xx[x] // ReleaseHold // Evaluate] /. xx[x_] -> x) // ToString[#, InputForm] & // StringTake[#, {6, -2}] & ToExpression@% == ToExpression@s1 (Hold[ToExpression[s2, InputForm, Hold] /. x_Integer :> xx[x] // ReleaseHold // Evaluate] /. xx[x_] -> x) // ToString[#, InputForm] & // StringTake[#, {6, -2}] & ToExpression@% == ToExpression@s2 (Hold[ToExpression[s3, InputForm, Hold] /. x_Integer :> xx[x] // ReleaseHold // Evaluate] /. xx[x_] -> x) // ToString[#, InputForm] & // StringTake[#, {6, -2}] & ToExpression@% == ToExpression@s3 

"-7 - 3 + 1*2 + 4 + 5 + 6 + 8 + 9" True "((-4 + 1*2 + 3 + 5)*7)/6 + 8 + 9" True "-9 + 1 + 2 - 3*4*5 + 6*(7 + 8)" True 
$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.