0

I have a question regarding some code to process some names or numbers from a file I'm reading. So the text in the file looks like this:

Imp;1;down;67
Comp;3;up;4
Imp;42;right;87

As you can see , there are 3 lines with words and numbers delimited by the character ';' . I want to read each line at a time, and split the entire string in one line into the words and numbers , and then process the information (will be used to create a new object with the data). Then move on to the next line, and so on, until EOF.

So, i want to read the first line of text, split it into an array of strings formed out of the words and numbers in the line , then create an object of a class out of them. For example for the first line , create an object of the class Imp like this Imp objImp(Imp, 1, down, 67) .

In Java i did the same thing using information = line.split(";")' (where line was a line of text) and then used information[0], information[1] to access the members of the string array and create the object. I`m trying to do the same here

LogicStuff
  • 19,397
  • 6
  • 54
  • 74
Alex
  • 127
  • 3
  • 12
  • 2
    It looks like your code reads one line, prints it, and repeats until there's nothing left to read. This matches your description of things I think... so what's the problem? _it doesn't stop after the first line so i can insert the code i need_ -- um, huh? You haven't described your problem very well at all, and you don't seem to have added any code to process the line (`output`) other than to print it. – mah Jan 06 '16 at 19:19
  • 1
    You are inviting a crash with the constant `256` in your `getline`. You should use `sizeof(output)` here. – Logicrat Jan 06 '16 at 19:27
  • @mah I didn't explain what i'm trying to do properly, let me try again. So, i want to read the first line of text, split it into an array of strings formed out of the words and numbers in the line , then create an object of a class out of them. For example for the first line , create an object of the class Imp like this `Imp objImp(Imp, 1, down, 67)` . I Java i did the same thing using 'information = line.split(";")' (where line was a line of text) and then used 'information[0]', 'information[1]' to access the members of the string array and create the object. I`m trying to do the same here – Alex Jan 06 '16 at 19:39
  • @Logicrat - That was just for testing, but thanks for the heads up – Alex Jan 06 '16 at 19:41
  • See also: [Split a string in C++?](http://stackoverflow.com/a/236803/421195) – paulsm4 Jan 06 '16 at 20:31

2 Answers2

3

Don't use char array for buffer, and don't use std::istream::eof. That's been said, let's continue in solving the problem.

std::getline is simmilar to std::istream::getline, except that it uses std::string instead of char arrays.

In both, the parameter delim means a delimiting character, but in a way that it's the character, which when encountered, std::getline stops reading (does not save it and discards it). It does not mean a delimiter in a way that it will magically split the input for you between each ; on the whole line.

Thus, you'll have to do this:

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

...

std::ifstream myFile("D:\\stuff.txt"); // one statement

if (myFile.is_open()) {
    std::string line;

    while (std::getline(myFile, line)) { // line by line reading
        std::istringstream line_stream(line);
        std::string output;

        while (std::getline(line_stream, output, ';')) // line parsing
            std::cout << output << std::endl;
    }
}

We construct a std::istringstream from line, so we can parse it again with std::getline.

Community
  • 1
  • 1
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
  • 1
    [Live Demo](http://coliru.stacked-crooked.com/a/d092549929aa1898) of your code in action. – AndyG Jan 06 '16 at 19:49
  • Thanks , the code does work fine , but i improperly formulated my question the first time. meanwhile i edited the initial question , see the last part regarding what i am trying to achieve in the now-edited initial question , in case you have any ideea – Alex Jan 06 '16 at 20:10
  • @Alex Instead of printing `output`, you push it into a `std::vector` re-created each iteration of the outer loop, then check its size, using [these functions](http://en.cppreference.com/w/cpp/string/basic_string/stol), if you need to convert `std::string` to integer. – LogicStuff Jan 06 '16 at 20:18
  • @Alex And it could be done in a sightly different way, overloading `operator>>` for `Imp`. – LogicStuff Jan 06 '16 at 20:18
  • @LogicStuff Thanks. The vector part i should be able to pull off , found the documentation for it (http://www.cplusplus.com/reference/vector/vector/) , so i should be good. As far as overloading, i haven`t tried that in C++ , need to investigate that further. Marked your answer as correct, thanks a lot for the help. – Alex Jan 06 '16 at 20:28
1

One other (slightly different) alternative:

/*
 * Sample output:
 *   line:Imp;1;down;67
 *     "Imp", "1", "down", "67"
 *   line:Comp;3;up;4
 *     "Comp", "3", "up", "4"
 *   line:Imp;42;right;87
 *     "Imp", "42", "right", "87"
 *   line:Imp;42;right;87
 *     "Imp", "42", "right", "87"
 */
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

void split(const std::string &s, char delim, std::vector<string> &fields)
{
    fields.clear();
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        fields.push_back(item);
    }
}

void print (std::vector<string> &fields)
{
  cout << "  ";
  for (size_t i = 0; i < fields.size() - 1; i++)
    cout << "\"" << fields[i] << "\", ";
  cout << "\"" << fields[fields.size()-1] << "\"" << endl;
}

int main ()
{
  std::ifstream fp("tmp.txt");
  std::string line;
  while (!fp.eof()) {
    fp >> line;
    cout << "line:" << line << endl;
    std::vector<std::string> fields;
    split(line, ';', fields);
    print(fields);
  }
  fp.close();
  return 0;
}
paulsm4
  • 114,292
  • 17
  • 138
  • 190