The easiest way to read formatted input in C++?
Asked Answered
T

4

21

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?

Tarshatarshish answered 7/7, 2012 at 11:31 Comment(0)
V
16

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.

Violaceous answered 7/7, 2012 at 11:35 Comment(1)
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 stlTarshatarshish
C
30
#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;
}
Cyrilla answered 7/7, 2012 at 11:40 Comment(1)
+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).Openandshut
V
16

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.

Violaceous answered 7/7, 2012 at 11:35 Comment(1)
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 stlTarshatarshish
C
6

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.

Cataplexy answered 7/7, 2012 at 11:44 Comment(0)
S
4

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;
}
Stray answered 7/7, 2012 at 11:40 Comment(3)
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.Rocher
@Rocher not now=( liveworkspace.org/code/b66dcfa19ce7620fb7b9e4c203c42f43Stray
@Stray 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.Rocher

© 2022 - 2024 — McMap. All rights reserved.