Need Help Parsing Text File, WAY Over My Head

I need help parsing a text file that's based upon the "last" command in Linux, where it shows users' login info. I need to store the data in the Login class' member data, and print them out in a specific order for each line. This project is pretty over my head, and I'd love some help with it. I've been trying to get help on other forums for weeks, but now, near the deadline, I've decided to ask here. First, here's what I want the actual output for this file to be, verbatim:

1
2
3
4
5
6
7
8
9
April 25 10.253.65.122 (00:24)
April 25 10.253.88.10 (00:25)
April 25 10.253.88.10 (00:33)
April 25 10.253.65.122 (00:08)
April 25 10.253.65.122 (00:01)

wtmp begins Sat Apr  8 19:49:05 2017

Total duration logged in: (01:31)



Here's my text file:

1
2
3
4
5
6
7
8
mhossain pts/1        10.253.65.122    Tue Apr 25 12:20   still logged in
mhossain pts/2        10.253.65.122    Tue Apr 25 11:54 - 12:19  (00:24)
mhossain pts/1        10.253.88.10     Tue Apr 25 11:53 - 12:18  (00:25)
mhossain pts/2        10.253.88.10     Tue Apr 25 11:19 - 11:53  (00:33)
mhossain pts/1        10.253.65.122    Tue Apr 25 11:13 - 11:21  (00:08)
mhossain pts/1        10.253.65.122    Tue Apr 25 11:00 - 11:01  (00:01)

wtmp begins Sat Apr  8 19:49:05 2017



Here's main.cpp:

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
54
55
56
57
58
59
#include <iostream>
#include <fstream>
#include "Login.h"


std::ostream& operator<< ( std::ostream& out, Login& b) //Overload << to print out parsed data
{
    
   out << b.login_month << " " << b.login_day << " " << b.ip_address << " " << b.login_duration << std::endl;
    
    return out; //Return out to keep lh operand as ostream, so all params pass (cout << login1 << login2)
        
    
}//End operator<< overload

int main(int argc, const char * argv[]) //Take userid as param
{
    
    if (argc != 2) //No need to second parameter
    {
        
        std::cout << "Please Try Again Using Only One Parameter" << std::endl;
        exit(0);
        
    }
    
    
    std::string fileName = (std::string)argv[1] + ".txt"; //Append argc[l] argument to .txt file name
    std::ifstream login_data (fileName); //Open file
    std::string line; //String variable for getline parameter
    Login* login = new Login("","", "", 0,0); //Dynamic object
    
    while (std::getline(login_data, line)) //Get entire line
    {
        
        if (line.find("still logged in") != std::string::npos) //Search for instance of "still logged in"
        {
            
            continue; //Break current iteration if record shows user still logged in
            
        }
        
        std::getline(login_data, line, ' ');
        login->set_user_id(line);
        std::cout << login->get_user_id() << " ";
        
        
        
    }
    
    
    
    login_data.close(); //Close file
    delete login; //Deallocate login
    login = NULL; //Free up memory location
    
    
    
}//End main() 


Here's Login.h:

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
#include <string>

class Login
{
    
    std::string user_id;
    std::string ip_address;
    std::string login_month;
    int login_day;
    int login_duration; //Minutes
    
public:
    
    Login(std::string, std::string, std::string, int, int);
    friend std::ostream& operator<<(std::ostream&, Login&);
    void set_user_id (std::string);
    void set_ip_address(std::string);
    void set_login_month(std::string);
    void set_login_day(int);
    void set_login_duration(int);
    std::string get_user_id();
    std::string get_ip_address();
    std::string get_login_month();
    int get_login_day();
    int get_login_duration();
    
    
}; //Login class 


And, finally, here's Login.cpp:

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include "Login.h"
#include <string>
#include <iostream>


Login::Login(std::string a, std::string b, std::string c, int d, int e)
{
    
    user_id = a;
    ip_address = b;
    login_month = c;
    login_day = d;
    login_duration = e;
    
}

void Login::set_user_id(std::string a)
{
    
    user_id = a;
    
}

void Login::set_ip_address(std::string a)
{
    
    ip_address = a;
    
}

void Login::set_login_month(std::string a)
{
    
    login_month = a;
    
}

void Login::set_login_day(int a)
{
    
    login_day = a;
    
}


void Login::set_login_duration(int a)
{
    
    login_duration = a;
    
}

std::string Login::get_user_id()
{
    
    return user_id;
    
}

std::string Login::get_ip_address()
{
    
    return ip_address;
    
}

std::string Login::get_login_month()
{
    
    return login_month;
    
}

int Login::get_login_day()
{
    
    return login_day;
    
}

int Login::get_login_duration()
{
    
    return login_duration;
    
}
Last edited on
In the program below I've used struct Login to read the file – since it uses the public ctor this doesn't make any difference but for your class Login code you should also const qualify the methods and their arguments wherever possible as well as passing by reference
Also note in the file it says 'Apr' but has to be printed as 'April' – this is an exercise left for you (hint: you could use an enum or have the switch statements directly inside the operator << overload) and consider using the <iomanip> library for aligning the printing a bit neater. There are comments in the code but shout if something's unclear:
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
//#include "test_header.h"

struct Login
{
    std::string user_id;
    std::string ip_address;
    std::string login_month;
    int login_day;
    int login_duration; //Minutes

    Login(const std::string& id, const std::string& address, const std::string& month, const int day, const int duration)
    : user_id(id), ip_address(address), login_month (month), login_day (day), login_duration(duration){}
};
std::ostream& operator<< ( std::ostream& out, const Login& b) //Overload << to print out parsed data
{

   out << b.login_month << " " << b.login_day << " " << b.ip_address << " " << b.login_duration << std::endl;

    return out; //Return out to keep lh operand as ostream, so all params pass (cout << login1 << login2)


}//End operator<< overload


int main() //Take userid as param
{
    std::vector<Login> logins{};
    std::ifstream inFile{"D:\\test.txt"};
    std::string startInfo{};

    if(inFile)
    {
        std::string dummy{};
        getline(inFile, dummy);//read and discard first line
        std::string line{};
        while (getline(inFile, line) )
        {
            if(line.empty())break;//breaks loop on penultimate line
            std::istringstream stream{line};
             std::string name {}; std::string address{}; std::string month{};
             int day{};  int duration;

            while (stream)
            {
                stream >> name;
                stream >> dummy;//pts
                stream >> address;
                stream >> dummy;//day of the week
                stream >> month;
                stream >> day;
                stream >> dummy;//start time -
                stream >> dummy;// character -
                stream >> dummy; // end time

                std::string timePeriod{};
                stream >> timePeriod;
                if(timePeriod.size())
                timePeriod = std::string{timePeriod.begin()+1, -- timePeriod.end()};//remove '(' and ')'

                std::istringstream durationStream{timePeriod};
                std::string durationString{};
                while (durationStream)
                {
                    getline(durationStream, dummy, ':') 
                    //removed '00: - check this in case duration > 1 hour (or 99 mins?)
                    && getline(durationStream, durationString);
                }
                std::istringstream timeStream{durationString};

                timeStream >> duration;
             }
             if(inFile)
            {
                logins.emplace_back(Login(name, address, month, day, duration));
            }
        }

        getline(inFile, startInfo);//last line

    }
    for (const auto& elem : logins)std::cout << elem ;

    std::cout << startInfo << "\n";
}

edit: your operator << also needs a bit of work on the duration field to get to the desired format
Last edited on
Topic archived. No new replies allowed.