How do I convert an arbitrary box specification extracted from a cell expression into an input expression?
This came up as a problem with my answer to Save Mathematica code in FullForm
syntax. In that context, pattern matching was being used to extract box specifications from notebook expressions read using Import
.
I thought that ToExpression
or MakeExpression
would do the job of box interpretation, but in some circumstances they do not.
Consider an input cell that contains the expression:
StringForm["a = ``", 1]
The cell expression for such a cell looks like this:
Cell[BoxData[
RowBox[{"StringForm", "[",
RowBox[{"\"\<a = ``\>\"", ",", " ", "1"}], "]"}]], "Input"]
I can take the BoxData
subexpression from this cell and use ToExpression
to obtain the same output as if I had evaluated the original cell:
ToExpression @
BoxData[
RowBox[{"StringForm", "[",
RowBox[{"\"\<a = ``\>\"", ",", " ", "1"}], "]"}]]
But now consider the following input expression:
StringForm["a = ``", 1]
You'll have to look closely to see the difference: the a
is in italics. Here is the corresponding cell expression:
Cell[BoxData[
RowBox[{"StringForm", "[",
RowBox[{"\"\<\!\(\*
StyleBox[\"a\",
FontSlant->\"Italic\"]\) = ``\>\"", ",", " ", "1"}], "]"}]], "Input"]
If I evaluate this cell normally, I get the expected result. But if I try applying ToExpression
to the BoxData
subexpression like before:
ToExpression @
BoxData[
RowBox[{"StringForm", "[",
RowBox[{"\"\<\!\(\*
StyleBox[\"a\",
FontSlant->\"Italic\"]\) = ``\>\"", ",", " ", "1"}], "]"}]]
an error occurs:
StringForm::string : String expected at position 1 in StringForm[]\) = '',
FontSlant->"\~\(\*\nStyleBox["a Italic, 1].
The same kind of error occurs for many, if not all, of the inline string box escape sequences. I've tried explicitly specifying the form to ToExpression
and MakeExpression
, but I get the same error. Which brings me to my question...
What do I have to do to emulate the way Mathematica interprets the boxes from an input cell expression?
I think this is a bug. Here is a work-around that worked on a couple of examples I tested:
Clear[toExpression];
toExpression[bd_BoxData] :=
ToExpression[bd /.
s_String :>
StringReplace[
StringReplace[s, "\n" :> ""],
ShortestMatch[(start : "\(\*") ~~ body__ ~~ (end : "\)")] :>
StringJoin[start, StringReplace[body, "\"" :> "\\\""], end]
]
];
For example, we start with your case:
In[747]:=
BoxData["\"\<\!\(\*
StyleBox[\"a\",
FontSlant->\"Italic\"]\) = ``\>\""]//toExpression
Out[747]= a = ``
If we examine the cell now, it is:
BoxData["\<\"\\!\\(\\*StyleBox[\\\"a\\\",FontSlant->\\\"Italic\\\"]\\)\ = ``\"\>"]
instead of
BoxData["\"\<\!\(\*StyleBox[\"a\",FontSlant->\"Italic\"]\) = ``\>\""]
(which is the initial one with newlines removed). And, I'd argue, this is what it should have been from the start. Now:
In[746]:= ToExpression@
BoxData["\<\"\\!\\(\\*StyleBox[\\\"a\\\",FontSlant->\\\"Italic\\\"]\\) = ``\"\>"]
Out[746]= a = ``
So this already works fine.
I don't know how universal this work-around it, but it seems to work for examples I tried. The main problem was that, when "stringifying" things like a
and Italic
, it should have been \\\"a\\\"
and \\\"Italic\\\"
rather than \"a\"
and \"Italic\"
- the escapes for escapes themselves were missing.
Honestly I am not sure what you're trying to do, but I suspect you will need to use the FrontEnd itself for processing. Here is a generic example:
FrontEndExecute@FrontEnd`CellPrint[
BoxData[RowBox[{"StringForm", "[", RowBox[{"\"\<\!\(\*
StyleBox[\"a\",
FontSlant->\"Italic\"]\) = ``\>\"", ",", " ", "1"}], "]"}]]
]
However, I don't know what format you actually want to get.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With