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

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

  • 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.


    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.

    链接地址: http://www.djcxy.com/p/50832.html

    上一篇: 使用.Net WebRequest Factory

    下一篇: C ++ / Boost:编写更强大的sscanf替换