C++ Парсинг строки

439
04 мая 2017, 15:29

Привет всем. Есть строка с аргументами к примеру "Привет, меня зовут %1, мне %2 лет. Я живу в %3". Входные данные такие char array[64] = "Антон|15|Архангельске"; Нужно распарсить строку и подставить данные в аргументы строки, далее вывести строку.

Answer 1

Чтобы лексемы из строки вытащить, можно использовать 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;
}

В этом варианте легче совершить ошибку и сложнее отследить как крайние случаи себя ведут.

Answer 2

Создаете новую строку, в которую копируете все символы исходной кроме "форматов", вместо которых копируете соответствующие элементы array[].

Ну, а для его разбора (запоминаете в еще одном массиве указатели на слова) можно использовать и strtok() (только учтите, strtok неприменим к константам и необратимо меняет строку, к которой применяется).

Скорее всего, результирующую строку имеет смысл создавать в "динамической" памяти, поскольку ее размер заранее не известен (используете, например, malloc), наращивая ее размер по необходимости (например, вызывая realloc).

READ ALSO
Игнорирование delete для указателя на объект в статической памяти

Игнорирование delete для указателя на объект в статической памяти

"Использование оператора delete на указателе на объект, который не был создан при помощи оператора new, создает непрогнозируемый результат" (сайт...

279
OpenGl и ввод значений

OpenGl и ввод значений

Здравствуйте, помогите пожалуйста

348
Класс для pаботы с комплексными числами. [требует правки]

Класс для pаботы с комплексными числами. [требует правки]

Подскажите, как создать наследников класса: 1класс, хранящий число так же в виде строки и имеющий методы перевода строки в число и назад; 2

224
JavaScript: привязка контекста [дубликат]

JavaScript: привязка контекста [дубликат]

На данный вопрос уже ответили:

245