2

I have a text file containing sort of a graph presentation, as such:

7

{5, 2, 3}, {1,5}, { }, { }, {3}, { }, { }

Now, I know how to read a file and get in into an int

    while ((n = myfile.get()) != EOF) 

or into a string line by line

    getline (myfile,line)

The problem I have, is that with both of these options I can't really seem to compare every character I extract and check if it's a number or a "," or "{" or "}". Is there a simple way of doing that? I've been banging my head with this for hours since yesterday. I've tried some isdigit and casting, but that didn't work for me as well and really complicated stuff.

Ran Lavi
  • 25
  • 6
  • What did you try? Because if the question is how do i parse a file in c++, google has about 1000000 answers to that question. – Fantastic Mr Fox May 25 '18 at 07:49
  • Have a look at strtok - http://www.cplusplus.com/reference/cstring/strtok/ – auburg May 25 '18 at 07:59
  • @Fantastic Mr Fox I know you're only trying to help, but like I've written, I banged my head for hours with this. including searching Google obviously, but I didn't find something that helped me solve this. – Ran Lavi May 25 '18 at 08:09
  • @auburg I've encountered this during my searches yesterday. But I wasn't able to effectively use it. I'll explain my problems with it. I don't have a problem with printing, that's easy and there's no need for that at the moment. I want to really COMPARE my characters one by one, cause for each character I want to do something else(the options for characters are digit, ",", "{", "}", and blank). Also, stuff like "{5" is for me two different characters, which I'll want to perform different actions for encountering each. – Ran Lavi May 25 '18 at 08:17
  • @Rosh You'll need to do it in two steps - one call of strtok to extract } and then another call to extract { and , – auburg May 25 '18 at 08:33

2 Answers2

0

The easiest solution, I think, would be to get your hands dirty a bit, by reading the file char by char. I suggest you store the sets in a vector of vectors of ints (visualize it like a 2D array, a matrix, if you like).

If the i-th set is empty, then the i-th vector will be empty too.

In the loop in which you will parse the characters, you will skip the opening curly braces and commas. You will do similarly for the closing curly braces, except from the fact that you would need to update an index, which will help us update the index-th vector.

When we actually read a digit, then you can convert a char to an int.

Complete example:

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

int main(void) {
    char ch;
    fstream fin("test.txt", fstream::in);
    if(!fin) {
        cerr << "Something is wrong...! Exiting..." << endl;
        return -1;
    }
    int N; // number of sets
    fin >> N;
    vector<vector<int> > v;
    v.resize(N);
    int i = 0;
    while (fin >> ch) {
            //cout << ch << endl;
        if(ch == '{' || ch == ',')
            continue;
        if(ch == '}') {
            i++;
            continue;
        }
        v[i].push_back(ch - '0');
    }
    if(i == N) {
        cout << "Parsing the file completed successfully." << endl;
    } else {
        cout << "Parsed only " << i << " sets, instead of " << N << endl;
    }
    for(size_t i = 0; i < v.size(); ++i) {
        if(v[i].size() == 0)
            cout << i + 1 << "-th set is empty\n";
        else {
            for(size_t j = 0; j < v[i].size(); ++j)
                cout << v[i][j] << " ";
            cout << endl;
        }
    }
    return 0;
}

Output:

gsamaras@aristotelis:/Storage/homes/gsamaras$ g++ main.cpp

gsamaras@aristotelis:/Storage/homes/gsamaras$ ./a.out 
Parsing the file completed successfully.
5 2 3 
1 5 
3-th set is empty
4-th set is empty
3 
6-th set is empty
7-th set is empty

Important note: This should serve as a starting point, since it won't treat numbers that have more than one digits. In this case, you will to read up to the comma, or the closing curly brace, to make sure that you read all the digits of the numbers, then convert from string to integer, and then store it in the corresponding vector.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • Regarding the numbers, I get your point and thought earlier about using a flag to check if last char was a digit, and only if it was and the current char isn't,then to store it. Your method sounds a lot cleaner. – Ran Lavi May 25 '18 at 08:33
  • @Rosh I see that you tried a lot, that's why I spend some time writing an answer that may help. =) – gsamaras May 25 '18 at 08:34
  • Thank you very much! I've tried to edit my comment, but that took ages since I was checking and understanding your code while doing so. You've really helped me a lot, since I didn't even thought about the N to i comparison. Not to mention I wasn't aware that " char - '0' " is converting char to int! Now hopefully I'll be able to implement the pseudo code I've written two days ago for to the problem itself, after I'll successfully read and extract the file. – Ran Lavi May 25 '18 at 09:05
  • 1
    Done. For some reason I remembered that due to my low reputation I can't do that, like with the up/down vote. But apparently I remembered wrong. Thanks again! – Ran Lavi May 25 '18 at 10:31
0

Its better to read character by character as follows:

#include<iostream>
#include<fstream>
#include<string>
using namespace std;

int main()
{
    string line;
    int lineNum = 0;
    ifstream myfile ("file.txt");
    if (myfile.is_open())
    {
        while ( getline (myfile, line) )
        {
            // Identifying the type of charcter
            char a;
            cout << "Line Number " << ++lineNum << ": ";
            for(int i = 0; i < line.length(); i++)
            {
                a = line[i];
                cout << "\n\t" << a;
                if((a >= 32 && a <= 47) || (a >= 58 && a <= 64) || (a >= 91 && a <= 96) || (a >= 123 && a <= 126))
                {
                    cout << "\t(This character is either a Punctuation or arithmetic mark.)";
                    // If you don't want to porcess these character, then you may 'continue' to the next sub string
                }
                else if(a >= 48 && a <= 57)
                {
                    cout << "\t(This character is a number.)";
                    // If you want to change the number ot int, you can use atoi or stoi
                }
                else if(a >= 65 && a <= 90)
                    cout << "\t(Capital letter)";
                else if(a >= 97 && a <= 122)
                    cout << "\t(Small letter)";

            }
            cout<<endl;
        }
        myfile.close();
    }
    else
        cout << "Unable to open file";
    return 0;
}

I hop this helps.

  • I've tried your method as well, reading line by line, only numbers and ",". When again, at the beginning there's a number. representing the number of lines this time. But I encountered an error regarding the vector.. Says I'm out of range, but no really sure where. – Ran Lavi May 25 '18 at 19:43
  • And now apparently I can't put in the entire code in the comment, so not sure you'll be able to help me with that. I've actually debugged it for a while, and it appears as though it doesn't go pass for(int i = 0; i < line.length(); i++) which is pretty strange, but not sure you can guess my problem without the code... – Ran Lavi May 25 '18 at 19:51