C ++ / Boost: написание более мощной замены sscanf - PullRequest
7 голосов
/ 18 февраля 2011

Я хочу написать функцию на C ++ для замены sscanf на языке C, который назначает совпадения для итератора.

В принципе, я хочу что-то вроде:

string s = "0.5 6 hello";
std::vector<boost::any> any_vector;
sscanv(s, "%f %i %s", any_vector);
cout << "float: " << any_cast<float>(any_vector[0]);
cout << "integer: " << any_cast<integer(any_vector[1]);
cout << "string: " << any_cast<string>(any_vector[2]);

Точные детали могут отличаться, но вы поняли идею. Есть идеи для реализации?

Опции на данный момент вместе с проблемами на данный момент:

  • std :: istringstream : нет манипулятора для сопоставления константных выражений
  • Boost.Regex : не уверен, сработает ли это, и это кажется гораздо более сложным, чем необходимо для этого
  • Boost.Spirit : не думайте, что это будет работать для динамически генерируемых строк формата, и это также кажется более сложным, чем необходимо
  • sscanf : это будет работать, но нестандартно и т. Д., И его использование потребует больших затрат, поскольку количество аргументов определяется во время компиляции

Ответы [ 2 ]

2 голосов
/ 18 февраля 2011

Что об этом?

void sscanf(std::string str,
            const std::string& format,
            std::vector<boost::any>& result)
{
  std::string::const_iterator i = format.begin();
  while (i != format.end())
  {
    if (*i == '%')
    {
      ++i; // now *i is the conversion specifier
      char specifier = *i;

      ++i; // now *i is the next seperator
      std::string extract = str.substr(0, str.find(*i));

      switch (specifier) 
      {
        // matching an integer
        case 'i':
          result.push_back(boost::lexical_cast<int>(extract));
          break;
        // matching a floating point number
        case 'a': case 'e': case 'f': case 'g':
          result.push_back(boost::lexical_cast<float>(extract));
          break;
        // matching a single character
        case 'c':
          result.push_back(boost::lexical_cast<char>(extract));
          break;
        // matching a string
        case 's':
          result.push_back(extract);
          break;
        // Invalid conversion specifier, throwing an exception
        default:
          throw std::runtime_error("invalid conversion specifier");
          break;
      }
    }
    else
    {
      // if it's not a %, eat!
      str.erase(0, str.find(*i)+1);
      ++i;
    }
  }
}

Некоторые спецификаторы конверсий отсутствуют, но в основном это работает.

2 голосов
/ 18 февраля 2011

Если ваша строка формата определена во время компиляции, записано несколько variadic-template printf замен.Инвертирование должно работать достаточно хорошо.

Затем вы можете использовать оператор istream >> для чтения или функции c-stdlib.

...