Is it possible to convert the following list of strings to computable numbers with the comments preserved?

 str = {{{"8.0,1034(*g opx ksp pl ilm liq q *)"}, {"8.0,1035(*g opx ksp pl ilm liq q *)"}, 
         {"8.0,1037(*g opx ksp pl ilm liq q *)"}, {"8.0,1038(*g opx ksp pl ilm liq q *)"},   
         {"8.0,1039(*g opx ksp pl ilm liq q *)"}, {"8.0,1040(*g opx ksp pl ilm liq q *)"}},  
        {{"8.0,886(*g opx ksp pl ilm liq q  *)"}, {"8.0,889 (*g opx ksp pl ilm liq q *)"},   
         {"8.0,891(*g opx ksp pl ilm liq q  *)"}, {"8.0,894 (*g opx ksp pl ilm liq q  *)"},   
         {"8.0,896(*g opx ksp pl ilm liq q  *)"}, {"8.0,899 (*g opx ksp pl ilm liq q  *)"}}}

I'm after something like:

strc = {{{8.0,1034(*g opx ksp pl ilm liq q *)},....

Perhaps there is a way involving programatically adding the comments back onto the numbers after the numbers have been converted to an expression? Any Suggestions?

  • 3
    $\begingroup$ To do this robustly (expressions of any type) I believe you will need to parse the strings, and that was done very nicely in answer to this question: mathematica.stackexchange.com/q/17648/121 $\endgroup$ – Mr.Wizard May 31 '13 at 1:22
  • $\begingroup$ @Mr.Wizard I really like your link (+1), but I disagree that you need to parse strings. To get the string in the first place is hard to do programmatically (and is not addressed by Leonid). In case quotes are present in the expression, we cannot simply put ""'s around it. In case comments are present, we cannot resort to ToString, as it would delete the comments and destroy formatting. I have looked at front end stuff like CopyToClipBoard a while ago but I think I was unable to make a function that would "put quotes around an expression in a smart way", maybe I should ask a question about it. $\endgroup$ – Jacob Akkerboom May 31 '13 at 12:25
  • $\begingroup$ However, getting the cell expression programmatically is easy, as shown in my answer below. Also see my answer here, in your linked Q&A ,to see how we can also use this to delete comments and keep our formatting. (also @Kuba) $\endgroup$ – Jacob Akkerboom May 31 '13 at 12:27
  • $\begingroup$ @Mr.Wizard you can also get the string from the cell expression using ToString[NotebookRead[Cells[CellTags -> "targetCell"][[1]]][[1, 1]], InputForm], but I guess that should feel indirect. $\endgroup$ – Jacob Akkerboom May 31 '13 at 12:51
  • $\begingroup$ @Jacob Good points, and +1 on your answer. $\endgroup$ – Mr.Wizard Jun 2 '13 at 12:15

You can start with that.

StringCases["8.0,1034(*g opx ksp pl ilm liq q *)", 
 x__ ~~ y : ("(*" ~~ ___ ~~ "*)") :> {x, y}]

{{"8.0,1034", "(*g opx ksp pl ilm liq q *)"}}

And You can do with the first elements what You need.


I can not be passive after Jacob's remarks :) Following solution is based on his but simplified in order to avoid complicated procedures. I have also taken into account his comments to this post.

CellPrint[Cell[#, "Input"]] &@
 BoxData[ToBoxes[str] /. 
        "\"*" ~~ Verbatim["(*"] ~~ ___ ~~ Verbatim["*)\""]] &) :> 
    StringTake[x, {2, -2}]]

Definitely it works and is simple as it can be. I'm not sure why CellPrint[Cell[#, "Input"]] &@ BoxData[RowBox[{"{expr(*comm*)}"}]] gives us what we need. I hope Jacob Akkerboom will tell us more.

| improve this answer | |
  • 2
    $\begingroup$ +1 y : ("(*" ~~ ___ ~~ "*)") is nice. $\endgroup$ – DavidC May 30 '13 at 13:40
  • 2
    $\begingroup$ Pff Kuba, I helped you twice, and now you are stealing my points with impressive but weak magic :P. Note that StringMatchQ["()", ("(*" ~~ ___ ~~ "*)")]-> True ;). You might as well have left out the asterix (*), it has special meaning in string pattern matching. I'm kidding, I shouldn't care about points, but please also see my answer :). (@DavidCarraher) $\endgroup$ – Jacob Akkerboom May 30 '13 at 20:39
  • 1
    $\begingroup$ Cool, looking forward to that :). Anyway the pattern you are really after is "(" ~~ _?(MatchQ[#, "*"] &) ~~ ___ ~~ _?(MatchQ[#, "*"] &) ~~ ")". $\endgroup$ – Jacob Akkerboom May 30 '13 at 20:53
  • 1
    $\begingroup$ The above is nicer with Verbatim I guess, but I can't really show it as this will just format my code instead of display what I want. So we want something like "(" ~~ Verbatim["*"] ~~ ___ ~~... $\endgroup$ – Jacob Akkerboom May 30 '13 at 21:19
  • 1
    $\begingroup$ Wow Kuba, now this good stuff, +1 :). Much more practical than my answer, using the existing RowBox works fine, you make good use of its flexibility. Your (replacement) rule can be written a bit shorter, I'll suggest an edit, but its up to you what you like best :). $\endgroup$ – Jacob Akkerboom May 31 '13 at 10:06

About the first section: This simulates the behavior of Mathematica a bit more closely than Kuba's answer, creating an additional RowBox. However, the choice of how general the different aspects of the solution are may be a bit odd. Kuba's answer feels cleaner.

Use the OPs definition of str. The following will generate an input cell where the comments are (still) present as comments.

store[str_String] := (Sow[str]; token);

CellPrint[Cell[#, "Input"]] &@
      Rule, {Position[#[[1]], "token"], 
       Composition[RowBox, List] /@ #[[2, 1]]}]] &@
   Reap[ToBoxes@Map[Composition[store, ToString], str, {2, 2}]]]

Format preserving alternative

Suppose we start with the input cell

str = 
{{{"8.0,1034(*g opx ksp pl ilm liq q *)"}, {"8.0,1035(*g opx \
ksp pl ilm liq q *)"}}, {{"8.0,886(*g opx ksp pl ilm liq q  *)"}}}

We can give this a celltag by putting our cursor in the cell and doing Cell>Show Expression from the menu. The resulting cell will be the same as the cell printed by

    RowBox[{"str", "=", 

               "\"\<8.0,1034(*g opx ksp pl ilm liq q *)\>\"", "}"}], 

               "\"\<8.0,1035(*g opx ksp pl ilm liq q *)\>\"", 
               "}"}]}], "}"}], ",", 

             "\"\<8.0,886(*g opx ksp pl ilm liq q  *)\>\"", "}"}], 
          "}"}]}]], "Input", CellTags -> {"targetCell"}] // CellPrint

We can now do

NotebookRead[Cells[CellTags -> "targetCell"]] /. 
       "\"*" ~~ Verbatim["(*"] ~~ ___ ~~ Verbatim["*)\""]] &) :> 
   StringTake[x, {2, -2}] // CellPrint

to get a cell that is formatted in the same way as the cell with CellTag "targetCell", except for any formatting that may occur inside strings.

Format ignoring option using strings

Mr.Wizard hinted at a solution using strings, and Rm-rf gave the main code for this

CellPrint[Cell[#, "Input"]] &@
   UndocumentedTestFEParserPacket[ToString[str], False]

Which seems nice for this question, especially as having comments in strings hints at the expression str being the result of some Import command by Mathematica, or that this expression is at least generated in some way. In this case you don't care about existing formatting and in case of Import maybe it is an option to do all parsing by UndocumentedTestFEParserPacket. Who knows

| improve this answer | |
  • $\begingroup$ @geordie woops, I have added that. $\endgroup$ – Jacob Akkerboom May 30 '13 at 13:26
  • $\begingroup$ Very nice. It works perfectly. I think I'll have to do some reading about cell expressions.. Many Thanks! $\endgroup$ – geordie May 30 '13 at 13:36
  • $\begingroup$ @geordie yay :), then I am glad. I have done this kind of thing before without any boxes (and comments for that matter), but that was not so nice. This was good practise for me :). $\endgroup$ – Jacob Akkerboom May 30 '13 at 13:40
  • 1
    $\begingroup$ @geordie Ah yes, nice. I upvoted that question (which I don't do often) and favorited it. I wanted to present a solution yesterday but I had no time. I also saw your solution, but I don't like working with strings, I prefer held expressions. I always regret decisions like determining the scope of a variable. So I'm very interested in how we can do something like that afterwards :). $\endgroup$ – Jacob Akkerboom May 30 '13 at 13:55
  • 1
    $\begingroup$ You can save yourself the trouble of constructing the boxes by using UndocumentedTestFEParserPacket. For example, First@MathLink`CallFrontEnd@UndocumentedTestFEParserPacket[s, False] where s is a string $\endgroup$ – rm -rf May 31 '13 at 13:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.