Reputation: 97
I have written a template file which is as follows
Hello ${Name}
I like ${food}
I wanted to write a c++ code which generates the following code using the template file as reference
Hello John
I like Pasta
I like Pasta
I like Pasta
Is there a way to do this in C++? I came across "ctemplate", but I was not convinced. The application I am developing is cross-platform. ( I wanted to do something like string template in c#)
Upvotes: 1
Views: 415
Reputation: 393064
I've written a template expansion 'engine' using Boost Spirit before:
It's really versatile
I've just adapted it to your question's macro syntax. See it Live On Coliru
Okay, since performance appears to be the primary goal, here's a highly optimized expansion engine, in a benchmark:
#include <string>
#include <sstream>
#include <map>
#include <boost/utility/string_ref.hpp>
template <typename Range>
std::string expand(Range const& key)
{
if (key == "Name")
return "John";
if (key == "food")
return "Pasta";
return "??";
}
#include <iostream>
int main()
{
static const std::string msg_template =
"Hello ${Name}\n"
"I like ${food}\n"
;
std::ostringstream builder;
builder.str().reserve(1024); // reserve ample room, not crucial since we reuse it anyways
for (size_t iterations = 1ul << 22; iterations; --iterations)
{
builder.str("");
std::ostreambuf_iterator<char> out(builder);
for(auto f(msg_template.begin()), l(msg_template.end()); f != l;)
{
switch(*f)
{
case '$' :
{
if (++f==l || *f!='{')
{
*out++ = '$';
break;
}
else
{
auto s = ++f;
size_t n = 0;
while (f!=l && *f != '}')
++f, ++n;
// key is [s,f] now
builder << expand(boost::string_ref(&*s, n));
if (f!=l)
++f; // skip '}'
}
}
default:
*out++ = *f++;
}
}
// to make it slow, uncomment:
// std::cout << builder.str();
}
std::cout << builder.str();
}
It runs 2^22 (4,194,304) iterations in ~0.775s
See it Live On Coliru too (where it runs in ~1.8s).
Upvotes: 2
Reputation: 7491
The standard libraries have excellent facilities for everyday regex parsing (which is what you need), take a look at the docs here.
You need to learn about regex if you've never heard of it - this is at least one place outlining the details.
Alternately if you are concerned with performance and your task is literally as simple as you describe then writing your own parser should be very straight forward using two streams and seeking forward for the ${ escape sequence while copying across to the output stream substituting as needed.
Upvotes: 0