0

I have the following code which uses strtok which receives input from a txt file. The input in the txt file is:

age, (4, years, 5, months)
age, (8, years, 7, months)
age, (4, years, 5, months)

My code looks like:

char * point;
ifstream file;
file.open(file.c_str());

if(file.is_open())
{
    while(file.good())
    {
        getline(file, take);
        point = strtok(&take[0], ", ()");
    }
}

It is doing fine except the output of the 2nd age and 3rd age is missing. Can anyone tell me why are they missing?

Also I tried istringstream but whenever I enter my filename the program crashes.

char * point;
char take[256];
ifstream file;
file.open(file.c_str());

if(file.is_open())
{
    while(file.good())
    {
        cin.getline(take, 256);
        point =strtok(take,", ()");
    }
}
Xymostech
  • 9,710
  • 3
  • 34
  • 44
user1823986
  • 87
  • 3
  • 11

1 Answers1

5

Personally, I would use an std::istringstream but I would use it differently (... and, yes, I know that I could use sscanf() as well and that the code would be shorter but I dislike the type-unsafe interface)! I would play tricks with manipulators:

#include <iostream>
#include <sstream>
#include <string>

template <char C>
std::istream& skip(std::istream& in)
{
    if ((in >> std::ws).peek() != std::char_traits<char>::to_int_type(C)) {
        in.setstate(std::ios_base::failbit);
    }
    return in.ignore();
}

std::istream& (*const comma)(std::istream&) = &skip<','>;
std::istream& (*const open)(std::istream&) = &skip<'('>;
std::istream& (*const close)(std::istream&) = &skip<')'>;

struct token
{
    token(std::string const& value): value_(value) {}
    std::string::const_iterator begin() const { return this->value_.begin(); }
    std::string::const_iterator end() const   { return this->value_.end(); }
    std::string value_;
};

std::istream& operator>> (std::istream& in, token const& t)
{
    std::istreambuf_iterator<char> it(in >> std::ws), end;
    for (std::string::const_iterator sit(t.begin()), send(t.end());
         it != end && sit != send; ++it, ++sit) {
        if (*it != *sit) {
            in.setstate(std::ios_base::failbit);
            break;
        }
    }
    return in;
}

int main()
{
    std::istringstream input("age, (4, years, 5, months)\n"
                             "age , ( 8 , years , 7, months )\n"
                             "age, (4, year, 5, months)\n"
                             "age, (4, years 5, months)\n"
                             "age (4, years, 5, months)\n"
                             "age, 4, years, 5, months)\n"
                             "age, (4, years, 5, months)\n");
    std::string dummy;
    int         year, month;
    for (std::string line; std::getline(input, line); ) {
        std::istringstream lin(line);
        if (lin >> token("age") >> comma
            >> open
            >> year >> comma >> token("years") >> comma
            >> month >> comma >> token("months") >> close) {
            std::cout << "year=" << year << " month=" << month << "\n";
        }
    }
}
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • This looks a bit hefty, but very complete. – Xymostech Nov 17 '12 at 01:51
  • 1
    @Xymostech: Most of it is infrastructure which can be used in other contexts as well. Maybe it's time to look into a typesafe version similar to `scanf()` as well, built on `std::istream` and using variadic... – Dietmar Kühl Nov 17 '12 at 01:55
  • +1 For the manipulator tricks. The `main` code looks more readable. – Thomas Matthews Nov 17 '12 at 02:21
  • Sorry, is there any simpler way to do it? Because I just started learning c++ for 2months so I don't understand most of the implementation of your code. – user1823986 Nov 17 '12 at 03:51
  • @user1823986: You can skip the first manipulator and entirely work with `token`s. If you don't accept extra spaces, e.g., between `age` and `,`, you can then combine them. The `token` processing using fairly fundamental C++ techniques and, e.g., avoids defining a template. If you have concrete questions, I can answer them. – Dietmar Kühl Nov 17 '12 at 13:27