String templating

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
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
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" - I'm sorry, what is the question? About the note: ToString@Row[{##}, " "] & @@ RGBColor[1, 0, 0] – Kuba Jun 26 '14 at 10:24 @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. – joojaa Jun 26 '14 at 10:35 Ok, and there should be a template and the list, no function between? – Kuba Jun 26 '14 at 10:42 @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. – joojaa Jun 26 '14 at 10:44 3 Answers 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}}}]


-
Excellent, that's much better. Now all i need to do is understand whats going on but that's what the manual is for :) –  joojaa Jun 26 '14 at 10:55
@joojaa I'm glad it helps. Feel free to ask if you face any problems. –  Kuba Jun 26 '14 at 10:56
@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. –  Leonid Shifrin Jun 26 '14 at 19:38
@Leonid One general problem with Composition used to be that it unpacks packed arrays. r = RandomReal[1, 10000]; Composition[DeveloperPackedArrayQ, # &][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). –  Szabolcs Jun 28 '14 at 2:27
Note to people trying the above unpacking demonstration: Identity is auto-removed by Composition, so it is necessary to use #& in this example. –  Szabolcs Jun 28 '14 at 2:30
f[{a_, b_, c_}] :=
"AttributeBegin
Translate " <> #3 <> "
Color " <> #2 <> "
Surface \"constant\"
Sphere 0.1 -0.1  0.1 360.0
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}}]

-
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. –  joojaa Jun 26 '14 at 11:31

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." *)
`
-
Yeah, thats good since at the moment it is a bit painfull to do these. –  joojaa Jun 26 '14 at 14:07