2010-03-30 1 views
8

Ich möchte eine einfache C++ - String-basierte Template-Bibliothek, um Strings zur Laufzeit zu ersetzen.C++ - String-Vorlagenbibliothek

Zum Beispiel werde ich

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

Zur Laufzeit verwenden, möchte ich den Namen auf tatsächliches geändert werden.

fand ich ein Beispiel, www.stringtemplate.org aber ich wenig Angst, wenn ihre Gespräche über antlr usw.

+4

Die 'Vorlagen' Tag ist hier nicht geeignet. Das Ersetzen von Zeichenfolgen innerhalb einer Vorlagenzeichenfolge entspricht nicht der üblichen Bedeutung von Vorlagen in einem C++ - Kontext. –

+0

Mit 'actual one' meinen Sie eine Variable namens 'name', die im Bereich der String-Vorlage definiert ist? –

+0

Was ist die Frage? –

Antwort

14

Update: Das Projekt wird auf Github bewegt und in ctemplate umbenannt: https://github.com/OlafvdSpek/ctemplate

Von der neuen Projektseite:

wurde ursprünglich von Google-Vorlagen aufgrund ihrer Herkunft als Template-System genannt Wird für Google-Suchergebnisseiten verwendet. Jetzt hat es einen allgemeineren Namen, der seiner gemeinschaftseigenen Natur entspricht.


Haben Sie versucht, ctemplate Bibliothek von Google? Es scheint genau das zu sein, was Sie suchen:

Im Beispiel: http://code.google.com/p/google-ctemplate/

Ihr Beispiel wie dies umgesetzt werden würde.tpl:

Mein Name ist {{name}}

In 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; 
} 

Dann:

$ gcc example.cc -lctemplate -pthread 

$ ./a.out 

Mein Name ist John Smith

Beachten Sie, dass es auch eine Möglichkeit gibt, Vorlagen als Const-Strings zu schreiben, wenn Sie nicht möchten, dass Ihre Vorlagen in separaten Dateien geschrieben werden.

+1

https://github.com/OlafvdSpek/ctemplate ist das das Projekt? Die Beispielseite hat ein ähnliches Beispiel https://htmlpreview.github.io/?https://github.com/OlafvdSpek/ctemplate/blob/master/doc/index.html – TankorSmash

5

Können Sie sprintf verwenden?

Es gibt auch boost::format, wenn Sie boost hinzufügen möchten.

+3

Ich bin überrascht, dass Sie keine Morddrohungen bekommen, wenn Sie' sprintf' erwähnen. Aber das ist was ich benutze, also +1 :) –

+1

'snprintf', um Pufferüberläufe zu vermeiden. Siehe http://libslack.org/manpages/snprintf.3.html – Atmocreations

+1

\ * Todesdrohung \ * @John: Dort, jetzt ist diese Antwort vollständig. – GManNickG

4

Wenn Sie eine Funktion haben, die alle Vorkommen einer Zeichenfolge durch eine andere Zeichenfolge ersetzt:

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; 
} 

Dann können Sie dies tun:

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"); 
+0

nur um wählerisch zu sein (in der Praxis sehr unwahrscheinlich): Wenn Sie anstelle von 'Homer'' {{last_name}} 'als Wert von' {{first_name}} 'eingeben, erhalten Sie nicht das gewünschte Ergebnis ... –

+2

@Andre Holzner - hängt davon ab, was das gewünschte Ergebnis ist! –

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); 
} 
+0

Wenn Sie andere Tags haben, können Sie diese dann in einem Container speichern und die Schleife dann mit einer anderen Schleife, die den Container durchläuft, einbinden und so die Ersetzungsschleife mit jedem der Tags auf der Eingabezeichenfolge anwenden. Lassen Sie mich wissen, wenn Sie andere Tags haben, und ich werde den Beispielcode aktualisieren. – wilhelmtell

0

Es trieben sein könnte, aber Sie kann auch einen Blick auf boost::spirit werfen, und genauer gesagt, den 'Karma' Teil, der ein Textgenerator ist.

0

Wenn Sie viele Platzhalter haben, z. B. wenn Sie eine Makrovorlage für einen Brief haben, der automatisch erweitert werden soll, wäre eine einfache Tokenisierung einfacher zu warten, zu implementieren und später zu erweitern. Z. B

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

} 

Wenn jedoch das Problem einfach genug ist, und die Vorlage ist klein genug, gehen Sie einfach für eine der Antworten oben erwähnt.

1

Haben Sie eine Reihe von Inline-Funktionen in Betracht gezogen, die ostringstram anstelle von "String-Vorlagen" verwenden?

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

Es gibt andere alternative Ansätze, wenn Sie mehr Allgemeingültigkeit benötigen. Zum Beispiel eine Klassenhierarchie, in der die Basis eine "Format" -Schnittstelle bereitstellt und untergeordnete Klassen diese mit der entsprechenden variierenden Implementierung implementiert.

3

Wenn Sie neu in C++ sind, wird das Hinzufügen neuer Bibliotheken (Vorlage oder anders) zu Ihrer Installation nur die Lernkurve erhöhen. Dies können Sie einfach, elegant und effizient mit den integrierten Funktionen tun.

Im Gegensatz zu ähnlichen Antworten, macht dieser Code nur einen Durchlauf über den Eingang und skaliert gut mit großen Wörterbücher:

// 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; 
} 
0

Sie einen Blick auf Inja hat. Es ist eine einfache Header-Only-Vorlagen-Engine und erfüllt Ihre Anforderungen. Dort können Sie einfach anrufen

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