19

Is there any way to read a formatted string like this, for example :48754+7812=Abcs.

Let's say I have three stringz X,Y and Z, and I want

X = 48754 
Y = 7812
Z = Abcs

The size of the two numbers and the length of the string may vary, so I dont want to use substring() or anything like that.

Is it possible to give C++ a parameter like this

":#####..+####..=SSS.."

so it knows directly what's going on?

jogojapan
  • 63,098
  • 9
  • 87
  • 125
Loers Antario
  • 1,341
  • 4
  • 15
  • 23

4 Answers4

22
#include <iostream>
#include <sstream>

int main(int argc, char **argv) {
  std::string str = ":12341+414112=absca";
  std::stringstream ss(str);
  int v1, v2; 
  char col, op, eq; 
  std::string var;
  ss >> col >> v1 >> op >> v2 >> eq >> var;
  std::cout << v1 << " " << v2 << " " << var << std::endl;
  return 0;
}
perreal
  • 85,397
  • 16
  • 134
  • 168
  • 6
    +1 because this is the only answer that precisely takes into account the actual question. The other answers don't, because **1. using boost is not the simplest way** (I admit it might be the most elagant way) and **2. scanf is not C++ style** (as mentioned by the author of the corresponding answer). – ChristophK Nov 03 '15 at 11:25
13

A possibility is boost::split(), which allows the specification of multiple delimiters and does not require prior knowledge of the size of the input:

#include <iostream>
#include <vector>
#include <string>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>

int main()
{
    std::vector<std::string> tokens;
    std::string s(":48754+7812=Abcs");
    boost::split(tokens, s, boost::is_any_of(":+="));

    // "48754" == tokens[0]
    // "7812"  == tokens[1]
    // "Abcs"  == tokens[2]

    return 0;
}

Or, using sscanf():

#include <iostream>
#include <cstdio>

int main()
{
    const char* s = ":48754+7812=Abcs";
    int X, Y;
    char Z[100];

    if (3 == std::sscanf(s, ":%d+%d=%99s", &X, &Y, Z))
    {
        std::cout << "X=" << X << "\n";
        std::cout << "Y=" << Y << "\n";
        std::cout << "Z=" << Z << "\n";
    }

    return 0;
}

However, the limitiation here is that the maximum length of the string (Z) must be decided before parsing the input.

hmjd
  • 113,589
  • 17
  • 194
  • 245
  • thanx alot for the answer but is there anything else other than boost or any external libraries.. is it possible to be done in standard c++ or at least stl – Loers Antario Jul 07 '12 at 11:40
4

You can use scanf. It is not overly C++ - ish, but it does the trick with remarkably few lines of code:

char a[101], b[111], c[121];
sscanf(":48754+7812=Abcs", ":%100[^+]+%110[^=]=%120s", a, b, c);
string sa(a), sb(b), sc(c);
cout << sa << "-" << sb  << "-" << sc << endl;

The idea is to specify the characters accepted by the strings that you read using a very limited regular expression syntax. In this case, the first string is read up to the plus, and the second string is read up to the equals sign.

Sergey Kalinichenko
  • 675,664
  • 71
  • 998
  • 1,399
3

for example.

#include <boost/regex.hpp>
#include <iostream>

int main()
{
   boost::regex re("\":(\\d+)\\+(\\d+)=(.+)\"");
   std::string example = "\":48754+7812=Abcs\"";
   boost::smatch match;
   if (boost::regex_match(example, match, re))
   {
      std::cout << "f number: " << match[1] << " s number: " << match[2] << " string: " << match[3]
      << std::endl;
   }
   else
   {
      std::cout << "not match" << std::endl;
   }
}

and second variant, work only with string.

#include <string>
#include <iostream>

int main()
{
   std::string s = "\":48754+7812=Abcs\"";
   std::string::size_type idx = s.find(":");
   std::string::size_type end_first = s.find("+", idx + 1);
   std::string f_number = s.substr(idx + 1, end_first - (idx + 1));
   std::cout << f_number << std::endl;
   std::string::size_type end_second = s.find("=", end_first + 1);
   std::string s_number = s.substr(end_first + 1, end_second - (end_first + 1));
   std::cout << s_number << std::endl;
   std::string::size_type string_end = s.find("\"", end_second);
   std::string str = s.substr(end_second + 1, string_end - (end_second + 1));
   std::cout << str << std::endl;
}
ForEveR
  • 52,568
  • 2
  • 101
  • 125
  • 1
    Regular expressions are a good suggestion in many such cases, +1 for that. Note that regular expression support is, however, available as part of C++ in C++11 -- there is no need to use Boost regex any more. – jogojapan Jul 07 '12 at 12:09
  • 1
    @jogojapan not now=( http://liveworkspace.org/code/b66dcfa19ce7620fb7b9e4c203c42f43 – ForEveR Jul 07 '12 at 13:16
  • 1
    @ForEveR Right. I should have checked, but indeed GCC's regex support is still not where it should be, esp. capture groups don't work. Plus, there are differences in the regex syntax. E.g. the standard way of doing `[\d]` in C++11 is `[[:digit:]]`. Anyway, as a final comment, support for C++11 regex is better if you use Clang. With the right syntax adjustments your example code should work there. – jogojapan Jul 07 '12 at 14:10