Formatted text file reading problem

This is the file.
R: 10
Steve Abrew 90 80 84 76
David Nag 93 87 90 80
Mike Black
Andrew Van Den 90 88 95 85
Chris Smith 86 74 90
Dennis Dudley 74 76 77 83
Leo Rice 95 75
Fred Flinstone 73 67 78 72
Dave Light 89 71 91 89
Hua Tran Du 81 79 80

I want read these from the file and create a variable for characters and another variable for integers separately. But not able to do it..

Here is my code:


#include <iostream>
#include <fstream>
#include <cstring>

using namespace std;

int main(int argc,char* argv[])
{
ifstream inFile;
inFile.open(argv[1]);

if(!inFile)
{
cerr<<"Couldn't find the file";
return -1;
}

string data;

getline(inFile,data,'\0');
cout<<data<<"\n";

return 0;
}

the output came now same as the file.. But everything is saved in string data.. But now how can i separate names and int from that string?

Much appreciated if you guyz help :)
Last edited on
If you intend to use argv[1]. you should first check that argc is greater than one.

My first thought on looking at the file data was a struct could be useful. It would contain firstname, lastname, and an array or vector of integers.

I didn't follow up on that, here I just focus on reading the file. This is incomplete, it may point the way.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

int main()
{
    ifstream fin("data.txt");
    
    string word;
    int number = 0;
    fin >> word >> number >> ws;
    
    if (word != "R:")
    {
        cout << "unexpected input " << word << "\nexiting\n";
        return 1;
    }
    cout << "number = " << number << '\n';
    
    for (int i=0; i<number; ++i)
    {
        string line;
        if (getline(fin, line))
        {   
            istringstream ss(line);
            string firstname;
            if (ss >> firstname)
                cout << "first name: " << firstname << '\n';
        }
        
    }
}


The important thing when reading from a file is to not assume that everything works, after each file access, check that it worked. Hence the if statements at lines 16 and 26. That's a minimum, there are a couple more checks that I omitted.

The next part which I think is the key to solving your task is the use of a stringstream at line 28. This allows a string to be treated just like it is a file, you can read from it in the same way. I only read the first string at line 30 - again with a check to see whether it succeeded. The second name could be read in the same way (as part of the same statement perhaps).

To read the integers, I'd suggest a while loop since there is a variable quantity.
1
2
3
int n;
while (ss >> n)
// do something 

Last edited on
i go your point.. But using
fin >> word >> number >> ws;
i am able to get the number as 10. the number is returning 0 as it was declared previously. But the number should be 10 as R: 10. maybe the problem is with the colon : . it is also not return the word as R. it can't read it. is there any way to ignore the colon so that the number reads 10?
Last edited on
Are you sure that the file is opened successfully? At least word should contain something, is it empty?
1
2
3
4
5
6
    ifstream fin("data.txt");
    if (!fin)
    {
        cout << "could not open file\n";
        return 1;
    }
yeah now it works.. thanks..

But i have go another question.. I got all the first name.. With this process,i will also get the last name but what about those name which consist of 3 words?

and also how do i get the integer numbers into another int array or variable to check the average?
what about those name which consist of 3 words?

Sorry, I didn't notice that when I looked at the file.
As it stands, that is difficult. Ideally there would be a different delimiter such as the tab character '\t' instead of just a space, after the end of the name. That makes it easy to read the entire name using getline with tab as a delimiter. But if everything must be separated by spaces it is not so easy.

As for reading the numbers, I gave a short example previously, that would be sufficient if all you need is to get the average, there would be no need for an array. Otherwise, the simplest way is to use a vector and just push_back each number after it is read from the file. Otherwise declare an array of sufficient size and manage the incrementing of the subscript yourself.


ok thanks... i think i will be able to get the average from that... thanks a lot..

But can u help me with getting the 3 names? can u show me how to do that? :/
But can u help me with getting the 3 names?

The easiest way is to edit the file (if possible/necessary) to make sure there is a tab character '\t' after the name, like this:
R: 10
Steve Abrew	90 80 84 76
David Nag	93 87 90 80
Mike Black
Andrew Van Den	90 88 95 85
Chris Smith	86 74 90
Dennis Dudley	74 76 77 83
Leo Rice	95 75
Fred Flinstone	73 67 78 72
Dave Light	89 71 91 89
Hua Tran Du	81 79 80
Then just use getline.
getline(ss, name, '\t')

If it isn't possible to change the file, then you would seem to be stuck with reading each item as a string, and then testing whether the strings can be converted to an integer - not much fun, but possible.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

int main(int argc, char* argv[])
{
    ifstream fin(argv[1]);

    string data;
    int number;
    fin>>data>>number;
   // cout<<data<<endl;

    if (data != "R:")
    {
        cout << "unexpected input " << data << "\nexiting\n";
        return 1;
    }
    cout << "number = " << number << '\n';

    for (int i=0; i<number; ++i)
    {
        string line;
        if (getline(fin, line))
        {
            istringstream ss(line);
            string firstname,lastname,thirdname;

            if (ss>>firstname>>lastname)
                cout << "First name: "<<firstname<<"\t Last name: "<<lastname<< '\n';
               // if(ss>> lastname)
                 //   cout<<"Last name: "<<lastname<<'\n';
        }

    }
}


i used this to get the firstname and lastname with the '\t'.... where should i use the getline?
When I tested my idea, instead of using firstname,lastname,thirdname, I simply used a single string for the whole name. Thus the ss>>firstname>>lastname would be replaced with the getline which reads the entire name.
ok i used it but the the output is just everything that is in the input... :/
but i need to separate strings and ints :(
If that is getting the entire line - including the integers, it's because the delimiter '\t' was not present.
http://www.cplusplus.com/reference/string/string/getline/
Note that the 3rd parameter is the delimiter. By default it is the newline, but you can choose any character, such as a comma, according to the need.

I still don't know whether you are or are not able to edit the file?
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

int main(int argc, char* argv[])
{
if (argc<2 || argc >2)
	{
		cout<<"Inappropriate arguments. Please input 3 arguments"<<endl;
		return -1;
	}
    ifstream fin(argv[1]);

    string data;
    int number;
    fin>>data>>number;


    if (data != "R:")
    {
        cout << "unexpected input " << data << "\nexiting\n";
        return 1;
    }
    cout << "number = " << number << '\n';

    for (int i=0; i<number; ++i)
    {
        string line;
        if (getline(fin, line))
        {

            istringstream ss(line);

            string fullname;

            if (getline(ss, fullname,'\t'))
                cout << "Fullame: " <<fullname<<endl;
               
        }

    }
}


This is the output:
1
2
3
4
5
6
7
8
9
10
11
number = 10
Fullame: 
Fullame: Steve Abrew 90 80 84 76
Fullame: David Nag 93 87 90 80
Fullame: Mike Black
Fullame: Andrew Van Den 90 88 95 85
Fullame: Chris Smith 86 74 90
Fullame: Dennis Dudley 74 76 77 83
Fullame: Leo Rice 95 75
Fullame: Fred Flinstone 73 67 78 72
Fullame: Dave Light 89 71 91 89
Last edited on
I still don't know whether you are or are not able to edit the file?
no... trying but not able to.. :(
this isnt working (getline(ss, fullname,' ') . as there is no tab spaces in the text file i used only ' ' but then only the 1st names come out as there is a space between firstname and lastname. :(
Something like this, perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <string>
#include <vector>
#include <sstream>

bool is_integer( const std::string& str )
{
    // http://en.cppreference.com/w/cpp/string/basic_string/stol
    try { std::stoi(str) ; }
    catch( const std::exception& ) { return false ; }

    return true ;
}

struct student
{
    std::string name ;
    std::vector<int> scores ; // https://cal-linux.com/tutorials/vectors.html
};

student parse( const std::string& line )
{
    student s ;

    std::istringstream stm(line) ;
    if( stm >> s.name ) // the first field must be part of name
    {
        std::string fld ;
        while( stm >> fld ) // for each subsequent field
        {
            // somewhat simplified (no validation that scores must follow name segments)
            if( is_integer(fld) ) s.scores.push_back( std::stoi(fld) ) ;
            else s.name += ' ' + fld ; // not integer, must be part of name
        }
    }

    return s ;
}

std::vector<student> parse( std::istream& stm )
{
    std::vector<student> all_students ;

    std::string line ;
    std::getline( stm, line ) ; // throw the first line away

    while( std::getline( stm, line ) ) // for each of the remaining lines
    {
        if( !line.empty() ) all_students.push_back( parse(line) ) ;
    }

    return all_students ;
}

http://coliru.stacked-crooked.com/a/63f651f58636d8f5
ok thanks.. i got it... thanks a lot :)
Topic archived. No new replies allowed.