代码之家  ›  专栏  ›  技术社区  ›  user90150

C++字符串模板库

  •  8
  • user90150  · 技术社区  · 16 年前

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

    例如,我将使用

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

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

    我找到了一个例子,www.stringtemplate.org,但当它谈到antlr等时,我有点害怕。

    9 回复  |  直到 8 年前
        1
  •  14
  •   matias    8 年前

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

    从新项目页面:

    最初被称为谷歌模板,由于其来源作为模板系统用于谷歌搜索结果页面。现在它有了一个更通用的名字,与它的社区性质相匹配。


    你试过谷歌的模板库吗?这似乎正是你想要的: http://code.google.com/p/google-ctemplate/

    您的示例实现如下:

    例如:第三方物流:

    我的名字是名字

    例如:

    #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
    

    我叫约翰·史密斯

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

        2
  •  6
  •   strager    16 年前

    你能用吗? sprintf ?

    还有 boost::format 如果你想包括增强。

        3
  •  4
  •   Daniel Earwicker    16 年前

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

    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");
    
        4
  •  3
  •   Potatoswatter    16 年前

    如果您对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;
    }
    
        5
  •  1
  •   Mark B    16 年前

    您是否考虑过使用ostringstram而不是“字符串模板”的一组内联函数?

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

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

        6
  •  1
  •   klar    8 年前

    你可以看看 Inja . 它是一个简单的、只包含头部的模板引擎,可以满足您的要求。在那里你可以打电话

    data["name"] = "world";
    inja::render("Hello {{ name }}!", data); // Returns "Hello world!"
    
        7
  •  0
  •   wilhelmtell    16 年前
    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);
    }
    
        8
  •  0
  •   Alexandre Hamez    16 年前

    可能有点过头了,不过你也可以看看 boost::spirit 更具体地说,是文本生成器的“业力”部分。

        9
  •  0
  •   Sridhar Iyer    16 年前

    如果您有许多占位符,例如,如果您有一个用于自动扩展的字母的宏模板,那么一些基本的标记化技术将更易于维护、实现和扩展。例如

    //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
    */
    
    }
    

    但是,如果问题足够简单,并且模板足够小,只需选择上面提到的其中一个答案。