Привет всем. Есть строка с аргументами к примеру "Привет, меня зовут %1, мне %2 лет. Я живу в %3". Входные данные такие char array[64] = "Антон|15|Архангельске"; Нужно распарсить строку и подставить данные в аргументы строки, далее вывести строку.
Чтобы лексемы из строки вытащить, можно использовать sregex_token_iterator
из <regex>
:
#include <ostream>
#include <regex>
#include <string>
#include <vector>
std::ostream& print(std::ostream& out, const std::string& format,
const std::vector<std::string>& args)
{
std::regex re("[^%]+|%%|%\\d+");
for (std::sregex_token_iterator i {format.begin(), format.end(), re, 0}, end;
i != end; ++i) {
std::string token {*i};
if (token == "%%") { // escaped %
out << '%';
} else if (token[0] == '%') { // positional parameter
unsigned long index = std::stoul(token.substr(1));
out << args.at(index-1);
} else { // print as is
out << token;
}
}
return out;
}
Пример использования:
#include <iostream>
int main()
{
char array[] = u8"Антон|15|Архангельске";
print(std::cout, u8"Привет, меня зовут %1, мне %2 лет. Я живу в %3",
split(array, '|')) << std::endl;
}
где split()
можно также определить, используя regex, или в простом случае, когда разделитель char
, можно std::stringstream
+ std::getline()
использовать:
#include <sstream>
#include <string>
#include <vector>
std::vector<std::string> split(const std::string& s, char sep)
{
std::vector<std::string> args;
std::istringstream ss {s};
for (std::string arg; std::getline(ss, arg, sep); )
args.push_back(arg);
return args;
}
Пример запуска:
$ c++ -std=c++11 *.cc && ./a.out
Привет, меня зовут Антон, мне 15 лет. Я живу в Архангельске
Для сравнения, можно посмотреть на (нерекомендуемый) вариант, который руками формат разбирает:
std::ostream& print(std::ostream& out, const std::string& format,
const std::vector<std::string>& args)
{
bool in_format = false;
size_t index = 0;
for (char c : format) {
if (in_format) {
if (std::isdigit(static_cast<unsigned char>(c))) { // build up index
index *= 10;
index += c - '0';
}
else {
in_format = false;
if (index) { // full number, print corresponding arg
out << args[index-1];
index = 0;
if (c != '%') {
out << c; // print as is
}
} else if (c == '%') { // %% case -- print % literally
out << c;
} else { // error XXX ignore
out << c;
}
}
}
else if (c == '%') {
in_format = true;
} else { // print as is
out << c;
}
}
if (index)
out << args[index-1];
return out;
}
В этом варианте легче совершить ошибку и сложнее отследить как крайние случаи себя ведут.
Создаете новую строку, в которую копируете все символы исходной кроме "форматов", вместо которых копируете соответствующие элементы array[].
Ну, а для его разбора (запоминаете в еще одном массиве указатели на слова) можно использовать и strtok() (только учтите, strtok неприменим к константам и необратимо меняет строку, к которой применяется).
Скорее всего, результирующую строку имеет смысл создавать в "динамической" памяти, поскольку ее размер заранее не известен (используете, например, malloc
), наращивая ее размер по необходимости (например, вызывая realloc
).
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
"Использование оператора delete на указателе на объект, который не был создан при помощи оператора new, создает непрогнозируемый результат" (сайт...
Подскажите, как создать наследников класса: 1класс, хранящий число так же в виде строки и имеющий методы перевода строки в число и назад; 2