Hello to all. There is a line with arguments for example "Hi, my name is% 1, I'm% 2 years old. I live in% 3" . Input data such char array [64] = "Anton | 15 | Arkhangelsk"; You need to parse the string and substitute the data into the arguments of the string, then output the string.

  • Check out sscanf - DNS
  • What can you say about strtok? The question is how to display the data, substituting the arguments, but without creating additional variables to store the arguments? - Disastricks
  • Well, if everything is so cunning - I would start from the 21st position (% 1) and scanned before the appearance of ", me" with parallel parsing of the 2nd line without additional. functions ... With strtok did not work - without comm. - DNS

2 answers 2

To pull tokens from a string, you can use sregex_token_iterator from <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; } 

Example of use:

 #include <iostream> int main() { char array[] = u8"Антон|15|Архангельске"; print(std::cout, u8"Привет, меня зовут %1, мне %2 лет. Я живу в %3", split(array, '|')) << std::endl; } 

where split() can also be defined using regex, or in the simple case when the char delimiter, you can use 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; } 

Startup example:

 $ c++ -std=c++11 *.cc && ./a.out Привет, меня зовут Антон, мне 15 лет. Я живу в Архангельске 

For comparison, you can look at the (non-recommended) option, which hands parses the format:

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

In this embodiment, it is easier to make a mistake and harder to track how extreme cases behave.

    Create a new line in which you copy all the characters of the source except "formats", instead of which you copy the corresponding elements of array [].

    Well, to parse it (remember pointers to words in another array), you can also use strtok () (just remember, strtok is not applicable to constants and irreversibly changes the string to which it is applied).

    Most likely, it makes sense to create the resulting string in the "dynamic" memory, because its size is not known in advance (use, for example, malloc ), increasing its size as needed (for example, causing realloc ).