7
$\begingroup$

I am pretty new to string processing in Mathematica. But I'm having some problems in doing simple string template filling to my mind elegantly. For example when doing export for my answer here, one of my solutions so far is using:

cat = StringJoin @@ (ToString /@ {##}) &; strvec = cat[#[[1]], " ", #[[2]], " ", #[[3]]] &; StringJoin[Map[cat["AttributeBegin Translate ", strvec[#[[3]]], " Color ", strvec[#[[2]]], " Surface \"constant\" Sphere 0.1 -0.1 0.1 360.0 Attribute \"light\" \"shadows\" \"on\" LightSource \"pointlight\" \"l", #[[1]], "\" \"intensity\" 1 \"lightcolor\" [", strvec[#[[2]]], "] AttributeEnd Illuminate \"l", #[[1]], "\" 1 "] &, {{1, Blue, {0, 0, -1}}, {1, Red, {3, 1.5, 1}}}]] 

But what I would really like to do is have a separate the template string from the code so its easy to change without touching the rest of the code. Ideally id want something like this:

lightTemplate = "AttributeBegin Translate $trans$ Color $color$ Surface \"constant\" Sphere 0.1 -0.1 0.1 360.0 Attribute \"light\" \"shadows\" \"on\" LightSource \"pointlight\" \"l$num$\" \"intensity\" 1 \"lightcolor\" [ $color$ ] AttributeEnd Illuminate \"$num$\" " 

Then somehow map my database to fill in values to $num$, $color$ etc... Like i would do in mostly any other high level language (python uses % or {} instead of $ but the idea is the same). I tried using StringFormat but that didn't work too well.

In a related note is there a nice way to turn something like:

RGBColor[1, 0, 0] 

to

"1 0 0"

$\endgroup$
4
  • 1
    $\begingroup$ I'm sorry, what is the question? About the note: ToString@Row[{##}, " "] & @@ RGBColor[1, 0, 0] $\endgroup$ Commented Jun 26, 2014 at 10:24
  • $\begingroup$ @Kuba I updated the question a bit. What i want is a template thats strings because im going to write it on disk and pass to others but i would like to separate the templates form code so that they can be easily managed manually. Nearly all other languages that i work with have some kind of string templating mechanisms. $\endgroup$ Commented Jun 26, 2014 at 10:35
  • $\begingroup$ Ok, and there should be a template and the list, no function between? $\endgroup$ Commented Jun 26, 2014 at 10:42
  • $\begingroup$ @Kuba I dont really care if theres a function i just want to hide the copmplexity to variable so that its easier to change your mind later. Im just not really sure how to proceed form here. $\endgroup$ Commented Jun 26, 2014 at 10:44

3 Answers 3

7
$\begingroup$

Maybe:

lightTemplate = "AttributeBegin Translate `5` `6` `7` Color `2` `3` `4` Surface \"constant\" Sphere 0.1 -0.1 0.1 360.0 Attribute \"light\" \"shadows\" \"on\" LightSource \"pointlight\" \"l$num$\" \"intensity\" 1 \"lightcolor\" [ `2` `3` `4` ] AttributeEnd Illuminate \"`1`\" "; conv = Composition[ StringJoin, ToString[#, StandardForm] & /@ # &, StringForm[lightTemplate, ##] & @@@ # &, Map[Style[#, NumberMarks -> False] &, #, {2}] &, Flatten[List @@@ #] & /@ # & ]; conv[{{1, Blue, {0, 0, -1}}, {1, Red, {3, 1.5, 1}}}] 

enter image description here

$\endgroup$
10
  • 1
    $\begingroup$ Excellent, that's much better. Now all i need to do is understand whats going on but that's what the manual is for :) $\endgroup$ Commented Jun 26, 2014 at 10:55
  • $\begingroup$ @joojaa I'm glad it helps. Feel free to ask if you face any problems. $\endgroup$ Commented Jun 26, 2014 at 10:56
  • 1
    $\begingroup$ @Kuba I agree. I don't consider this style the most powerful (in the sense that it does not really allow to introduce qualitatively more powerful abstractions), but it can be applied to the majority of tasks where Mathematica shines, and it is still considerably more expressive that the "usual" one where component functions are not singled out explicitly. $\endgroup$ Commented Jun 26, 2014 at 19:38
  • 2
    $\begingroup$ @Leonid One general problem with Composition used to be that it unpacks packed arrays. r = RandomReal[1, 10000]; Composition[Developer`PackedArrayQ, # &][r] I see that this doesn't unpack now in the cloud, which is great news! The unpacking problem was the reason why I made a mental note never to use Composition (after having been bitten a few times). $\endgroup$ Commented Jun 28, 2014 at 2:27
  • 2
    $\begingroup$ Note to people trying the above unpacking demonstration: Identity is auto-removed by Composition, so it is necessary to use #& in this example. $\endgroup$ Commented Jun 28, 2014 at 2:30
3
$\begingroup$
f[{a_, b_, c_}] := "AttributeBegin Translate " <> #3 <> " Color " <> #2 <> " Surface \"constant\" Sphere 0.1 -0.1 0.1 360.0 Attribute \"light\" \"shadows\" \"on\" LightSource \"pointlight\" \"l" <> #1 <> "\" \"intensity\" 1 \"lightcolor\" [ " <> #2 <> " ] AttributeEnd Illuminate \"l" <> #1 <> "\"" & @@ {ToString@a, strvec[b], strvec[c]} f[{1, Blue, {0, 0, -1}}] f[{1, Red, {3, 1.5, 1}}] 
$\endgroup$
1
  • $\begingroup$ Yes its better than mine. But despite the cryptic nature, cubas idea has the nice feature that the string is totally separate form the actualizing code, and its just one string. This means its much more trivial to change by any other end user and code shared between different templates. I need to meditate on the answers a bit before deciding. $\endgroup$ Commented Jun 26, 2014 at 11:31
3
$\begingroup$

In version 10 (available now through the programming cloud) you can use StringTemplate.

StringTemplate allows using named placeholders, classical numbered placeholders, or even embedding code that uses placeholders. See the documentation for many advanced usage examples.

Basic usage demonstrating both named and numbered templates:

template = StringTemplate["`name` is `2` years old."]; template["name" -> "Annie", 19] (* "Annie is 19 years old." *) 
$\endgroup$
1
  • $\begingroup$ Yeah, thats good since at the moment it is a bit painfull to do these. $\endgroup$ Commented Jun 26, 2014 at 14:07

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.