Строковая библиотека шаблонов C++

Я хочу простой C++ основанная на строке библиотека шаблонов к строкам замены во времени выполнения.

Например, я буду использовать

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

Во времени выполнения я хочу, чтобы имя было изменено на основе фактического.

Я нашел один пример, www.stringtemplate.org, но я мало испугал когда его переговоры о antlr и т.д.

9
задан wilhelmtell 30 March 2010 в 19:57
поделиться

8 ответов

Update: Проект переехал на Github и переименован в CTemplate: https://github.com/OlafvdSpek/ctemplate

С новой страницы проекта:

первоначально проект назывался Google Templates, что объясняется его происхождением как системы шаблонов, используемой для страниц результатов поиска Google. Теперь у него более общее название, соответствующее его природе, принадлежащей сообществу.


Пробовали ли вы использовать библиотеку CTemplate от Google? Похоже, это именно то, что вы ищете: 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

Меня зовут Джон Смит

Обратите внимание, что есть также способ записывать шаблоны как const-строки, если вы не хотите возиться с написанием шаблонов в отдельных файлах.

14
ответ дан 4 December 2019 в 07:34
поделиться

Рассматривали ли вы набор встроенных функций, которые используют ostringstram вместо «строковых шаблонов»?

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

Есть и другие альтернативные подходы, если вам нужно больше общего. Например, иерархия классов, в которой база предоставляет интерфейс «формата», а дочерние классы реализуют его с соответствующей изменяющейся реализацией.

1
ответ дан 4 December 2019 в 07:34
поделиться

Если у вас есть функция, которая заменяет все вхождения строки другой строкой:

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
ответ дан 4 December 2019 в 07:34
поделиться

Можете ли вы использовать sprintf ?

Также есть boost :: format , если вы хотите включить ускорение.

6
ответ дан 4 December 2019 в 07:34
поделиться

Если вы новичок в 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;
}
3
ответ дан 4 December 2019 в 07:34
поделиться

Если у вас много держателей мест, например, если у вас есть макрошаблон для письма, который вы хотите автоматически расширять, некоторую базовую токенизацию будет проще поддерживать, внедрять и расширять позже. Например

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

}

Однако, если проблема достаточно проста, а шаблон достаточно мал, просто выберите один из вышеупомянутых вариантов.

0
ответ дан 4 December 2019 в 07:34
поделиться
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);
}
0
ответ дан 4 December 2019 в 07:34
поделиться

Это может показаться излишним, но вы также можете взглянуть на boost :: spirit и, более конкретно, на «карму» часть, которая является текстовым генератором.

0
ответ дан 4 December 2019 в 07:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: