RandomCoder
RandomCoder

Reputation: 3

how to use istream_iterators to split an equation?

I'm trying to split a string like ( 1 + 2 ) into a vector and when using an istream_iterators<string> it doesn't split the parentheses so I get vector outputs like

(1 , + , 2) when I want ( , 1, + , 2 ,)

Is it possible to use istream_iterators to achieve this?

string eq = "(1 + 2)";

istringstream ss(eq);
istream_iterator<string> begin(ss);
istream_iterator<string> end;
vector<string> vec(begin, end);

Upvotes: -2

Views: 476

Answers (2)

You can do this by creating a custom type Token and using it with istream_iterator. Bonus feature: this code will parse multiple digits, multiple operators, and nested expressions. So enjoy. :)

#include <iterator>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include <cctype>

using namespace std;

class Token {
private:
  string val;
public:
  Token() : val("") {}
  Token(string& v) : val(v) {}
  friend istream& operator>>(istream &in, Token& tok);
  friend ostream& operator<<(ostream &out, Token& tok);
};

istream& operator>>(istream &in, Token& tok) {
  char c;
  string v;
  if (in >> c) {
    if (isdigit(c)) {
      v.push_back(c);
      while (in >> c && isdigit(c)) {
    v.push_back(c);
      }
      in.putback(c);
    } else if (c == ' ') {
      while (in >> c && c == ' ') ;
      in.putback(c);
    } else {
      v.push_back(c);
    }
  }
  tok = v;
  return in;
}

ostream& operator<<(ostream &out, Token& tok) {
  out << tok.val;
  return out;
}

int main() {
  string eq = "(1 + 2)";
  //eq = "(100 + 200)"; // multiple digits
  //eq = "(100 + 200 * 300)"; // extra operator
  //eq = "(100 + (200 * 300))"; // nested parens

  istringstream ss(eq);
  istream_iterator<Token> begin(ss);
  istream_iterator<Token> end;
  vector<Token> vec(begin, end);
  for (auto& x : vec) {
    cout << "[" <<  x << "] ";
  }
  cout << endl;
}

Upvotes: 1

John Zwinck
John Zwinck

Reputation: 249582

I don't think you can do it using istream_iterator. Instead, simply do it by hand:

vector<string> vec;
vec.reserve(eq.size() / 4); // rough guess
bool in_number = false;
for (char ch : eq) {
    if (isspace(ch)) {
        in_number = false;
    } else if (isdigit(ch)) {
        if (in_number) {
            vec.back().push_back(ch);
        } else {
            vec.emplace_back(1, ch);
            in_number = true;
        }
    } else {
        vec.emplace_back(1, ch);
        in_number = false;
    }
}

Upvotes: 0

Related Questions