C ++字符串模板库

时间:2010-03-30 19:30:16

标签: c++ string

我想要简单的基于C ++字符串的模板库来在运行时替换字符串。

例如,我将使用

string template = "My name is {{name}}";

在运行时,我希望根据实际名称更改名称。

我找到了一个例子,www.stringtemplate.org,但是在讨论antlr等时我有点害怕。

10 个答案:

答案 0 :(得分:14)

更新:项目已移至Github并重命名为CTemplate:https://github.com/OlafvdSpek/ctemplate

从新项目页面:

  

最初被称为Google模板,因为它起源于用于Google搜索结果页面的模板系统。现在它有一个更符合社区所有性的通用名称。


您是否尝试过Google的CTemplate库?它似乎正是您所寻找的:http://code.google.com/p/google-ctemplate/

您的示例将如下实现:

在example.tpl中:

  

我的名字是{{name}}

在example.cc中:

#include <stdlib.h>
#include <string>
#include <iostream>
#include <google/template.h>

int main(int argc, char** argv)
{
  google::TemplateDictionary dict("example");
  dict.SetValue("name", "John Smith");
  google::Template* tpl = google::Template::GetTemplate("example.tpl",
                                                        google::DO_NOT_STRIP);
  std::string output;
  tpl->Expand(&output, &dict);
  std::cout << output;
  return 0;
}

然后:

$ gcc example.cc -lctemplate -pthread

$ ./a.out
  

我的名字是John Smith

请注意,如果您不想在单独的文件中写入模板,还可以将模板编写为常量字符串。

答案 1 :(得分:6)

您可以使用sprintf吗?

如果你想包括提升,还有boost::format

答案 2 :(得分:4)

如果你有一个函数用一个字符串替换所有出现的字符串:

std::string replace_all(std::string str, const std::string &remove, const std::string &insert) 
{
    std::string::size_type pos = 0;
    while ((pos = str.find(remove, pos)) != std::string::npos)
    {
        str.replace(pos, remove.size(), insert);
        pos++;
    }

    return str;
}

然后你可以这样做:

std::string pattern = "My name is {{first_name}} {{last_name}} and I live in {{location}}";

std::string str = replace_all(replace_all(replace_all(pattern, 
                       "{{first_name}}", "Homer"), 
                       "{{last_name}}", "Simpson"), 
                       "{{location}}", "Springfield");

答案 3 :(得分:3)

如果您不熟悉C ++,在安装中添加新库(模板或其他)只会增加学习曲线。这是您可以使用内置功能简单,优雅,高效地完成的任务。

与类似的答案不同,此代码只对输入进行一次传递,并且可以很好地扩展到大型词典:

// header
#include <map>
#include <sstream>

typedef std::map< std::string, std::string > subst_map;

// implementation
using namespace std;

string do_substitutions( string const &in, subst_map const &subst ) {
    ostringstream out;
    size_t pos = 0;
    for (;;) {
        size_t subst_pos = in.find( "{{", pos );
        size_t end_pos = in.find( "}}", subst_pos );
        if ( end_pos == string::npos ) break;

        out.write( &* in.begin() + pos, subst_pos - pos );

        subst_pos += strlen( "{{" );
        subst_map::const_iterator subst_it
            = subst.find( in.substr( subst_pos, end_pos - subst_pos ) );
        if ( subst_it == subst.end() ) throw runtime_error( "undefined substitution" );

        out << subst_it->second;
        pos = end_pos + strlen( "}}" );
    }
    out << in.substr( pos, string::npos );
    return out.str();
}

// usage
pair< string, string > substitutions_init[] = {
    make_pair( "firstname", "homer" ),
    make_pair( "lastname", "simpson" )
};
subst_map substitutions
    ( substitutions_init, substitutions_init + sizeof(substitutions_init)/sizeof(*substitutions_init) );

int main() {
    cerr << do_substitutions( "Mr. {{lastname}}, {{firstname}} esquire", substitutions ) << endl;
}

答案 4 :(得分:1)

您是否考虑过使用ostringstram而不是“string templates”的一组内联函数?

inline std::string name_template(const std::string& name)
{
    std::ostringstream os;
    os << "My name is " << name;
    return os.str();
}

如果您需要更多的一般性,还有其他替代方法。例如,一个类层次结构,其中基类提供“格式”接口,子类使用适当的变化实现来实现它。

答案 5 :(得分:1)

您可以查看Inja。它是一个简单的,仅限标题的模板引擎,可以满足您的需求。在那里你可以打电话

data["name"] = "world";
inja::render("Hello {{ name }}!", data); // Returns "Hello world!"

答案 6 :(得分:0)

string skeleton = "My name is {{name}}";
string placeholder = "{{name}}";
string::size_type pos = skeleton.find(placeholder);
while( pos != string::npos ) {
    skeleton.replace(pos, placeholder.length(), "Gopalakrishnan");
    pos = skeleton.find(placeholder, ++pos);
}

答案 7 :(得分:0)

这可能有点矫枉过正,但您也可以查看boost::spirit,更具体地说,看一下作为文本生成器的“业力”部分。

答案 8 :(得分:0)

如果您有许多占位符,例如,如果您希望自动展开字母的宏模板,则稍后将更容易维护,实施和扩展一些基本标记。 E.g

//pseudocode
foreach word in line
{
  if word=={{name}} print getFromDB(name,entry)
  else if word=={{address}} print getFromDB(address,entry)
  ..
  ..
  else print word

/*
* to get rid of if-else-if tree, you can just check if starts with {{ and ends with }} and directly query the string against a db/map/hash
*/

}

但是,如果问题很简单,并且模板足够小,那就去找上面提到的答案之一。

答案 9 :(得分:0)

我为那些仍在寻找这样一个库的人创建了一个https://github.com/lexxmark/string_template

    stpl::string_template st("Hello {{name}}!");
    st.set_arg("name", "World");
    auto r = st.render();
    EXPECT(r, "Hello World!");

它也有一些不错的自定义项。