C++ стандартная замена для (s)printf
Я делаю серверное приложение на C++, и оно предоставляет HTML-страницу в ответ на HTTP-запросы.
Проблема в том, что в настоящее время моя веб-страница написана в виде постоянной строки в моем коде, и я вставляю другие строки, используя <<
оператор и std::stringstream
еще во время написания самой строки. Смотрите пример, чтобы прояснить ситуацию:
std::string first("foo");
std::string second("bar");
std::string third("foobar");
std::stringstream ss;
ss << "<html>\n"
"<head>\n"
"<title>Bitches Brew</title>\n"
"</head>\n"
"<body>\n"
"First string: "
<< first << "\n"
"Second string: "
<< second << "\n"
"Third string: "
<< third << "\n"
"</body>\n"
"</html>";
Бывает, хотя я не могу просто вставить содержимое в файл, потому что данные, смешанные со структурой HTML, изменятся во время выполнения. Это означает, что я не могу просто записать всю страницу в файл со строковыми значениями first
, second
, а также third
потому что эти значения будут меняться динамически.
Для первого запроса я отправлю страницу с first = "foo";
тогда как во втором запросе я бы first = "anything else"
,
Кроме того, я мог бы просто вернуться к sscanf/sprintf
от stdio.h
и вставьте текст, который я хочу - мне просто нужно заменить пропуски строк на правильный формат (%s
), прочитайте структуру HTML из файла и вставьте все, что я хотел.
Я хотел бы сделать это в C++, без функций библиотеки C, но я не мог понять, что использовать для этого. Каким будет стандартное решение C++ для этого?
4 ответа
Стандарт C++ не имеет прямого эквивалента (s)printf
как форматирование (s)printf
сам. Тем не менее, существует множество библиотек форматирования, которые предоставляют эту функциональность, например, библиотека cppformat, которая включает в себя реализацию Python на C++. str.format
и безопасно printf
,
Тем не менее, я бы порекомендовал использовать вместо этого движок шаблонов, см. Фреймворк HTML C++, библиотека шаблонов, библиотека генератора HTML.
Или вы всегда можете заново изобрести колесо и написать свой собственный шаблонизатор, читая файл и заменяя некоторые заполнители аргументами.
Вы можете получить желаемый результат следующим образом:
- Сохраните статический HTML-файл в файле с заполнителями для динамического текста
- Прочитайте файл HTML в
std::string
- Для каждого фрагмента динамического текста найдите его заполнитель в строке (
std::string::find
) и замените заполнитель на динамический текст (std::string::replace
). - Запишите измененную строку в конечный пункт назначения.
Как насчет:
void RenderWebPage(std::stringstream& ss, std::string& first, std::string& second, std::string& third)
{
ss << "<html>\n"
"<head>\n"
"<title>Bitches Brew</title>\n"
"</head>\n"
"<body>\n"
"First string: "
<< first << "\n"
"Second string: "
<< second << "\n"
"Third string: "
<< third << "\n"
"</body>\n"
"</html>";
}
И вы можете назвать это так:
std::stringstream ss;
std::string first("foo");
std::string second("bar");
std::string third("foobar");
RenderWebPage(ss, first, second, third);
first = "anything else";
RenderWebPage(ss, first, second, third);
second = "seconds too";
RenderWebPage(ss, first, second, third);
Если вы не хотите использовать фреймворк, как подсказывают другие ответы (правильно), я думаю, вы можете черпать вдохновение из этой маленькой программы:
#include <iostream>
#include <map>
using namespace std;
string instantiate_html(string const& templateHTML, map<string, string> const& replacements)
{
string outputHTML = templateHTML;
for (auto& entry : replacements)
{
string placeholder = "<$" + entry.first + "$>";
size_t it = outputHTML.find(placeholder);
if (it != string::npos)
{
outputHTML.replace(it, placeholder.size(), entry.second);
}
}
return outputHTML;
}
int main()
{
map<string, string> replacements;
replacements["name"] = "Mark";
replacements["surname"] = "Brown";
// Normally you would read this string from your template file
string templateHTML = "<html><body><$name$><$surname$></body></html>";
string outputHTML = instantiate_html(templateHTML, replacements);
cout << outputHTML;
return 0;
}