C++/Boost: Writing a more powerful sscanf replacement

女生的网名这么多〃 提交于 2019-12-05 23:31:04

问题


I want to write a function in C++ to replace C's sscanf that assigns the matches to iterator.

Basically, I want something like:

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]);

The exact details may vary, but you get the idea. Any ideas for implementation?

Options so far along with problems so far:

  • std::istringstream: there's no manipulator for matching constant expressions
  • Boost.Regex: not sure if this will work and it seems much more complicated than necessary for this
  • Boost.Spirit: don't think this will work for dynamically generated format strings and it also seems more complicated then necessary
  • sscanf: it would work, but is non-standard, etc, and using it would require a lot of overhead since the number of arguments is determined at compile time

回答1:


What's about that?

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

Some conversions specifiers are missing – but principally it works.




回答2:


If your format string is determined at compile time, there are some variadic-template printf replacements written. Inverting those should work reasonably well.

You could then use istream's >> operator for reading, or the c-stdlib functions.



来源:https://stackoverflow.com/questions/5035256/c-boost-writing-a-more-powerful-sscanf-replacement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!