0

I am trying to write a program that is to read in a text file which consists of 4 columns (time stamp, signed in/out, what is being signed out/in, user signing it out)

ex

    15:47:10 OUT: "RS5K_700.EXE" SYSTEM@ALNWSPCNTRCTR1
    15:47:10 IN: "RS5K_700.EXE" SYSTEM@ALNWSPCNTRCTR1
    16:07:48 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    16:10:15 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    16:11:28 IN: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    16:46:34 IN: "RS500.EXE" mlulchak@alnsvpmillterm
    17:01:49 OUT: "RS500.EXE" mlulchak@alnsvpmillterm
    17:49:32 IN: "RS500.EXE" mlulchak@alnsvpmillterm
    9:30:28 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    15:39:32 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    15:40:10 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    15:40:31 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    0:10:59 IN: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    1:28:20 IN: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    1:28:38 IN: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
    1:28:41 IN: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1

I want this program to sort the list and only write the lines that were not signed back in (i.e. if signed out there should be a later sign in in the list. The list is in order but time so no worries on that.)

Here is what I have so far:

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

    int main()
    {
    ifstream inFile;
    string array[2000][4];

    int count, i, j, h;
    inFile.open("test.rtf");

    if(!inFile){
    cout << "Unable to open file" << endl;
    exit(1);
    }
    i=0;
    while(!inFile.eof()) {
    inFile>> array[i][0]   >>array[i][1]   >>array[i][2] >>array[i][3];
    i++;
            }
        inFile.close();


    j=0;
    h=i;

    while(j<i-1)
    {   
cout << j;
count=j+1;

 if (array[j][1]== "OUT:")
 {
     while(count < i)
     {
         if(array[count][1]=="IN:" && array[count][2]==array[j][2] && array[count][3]==array[j][3])
         {
            for (int k = count; k < i; k++)
            {
            array[k][0] = array[k+1][0]; 
            array[k][1] = array[k+1][1];
            array[k][2] = array[k+1][2];
            array[k][3] = array[k+1][3];
            }
        array[i-1][0] = " ";
            array[i-1][1] = " ";
            array[i-1][2] = " ";
            array[i-1][3] = " ";
            i--;
            for (int k = j; k < i; k++){
            array[k][0] = array[k+1][0]; 
            array[k][1] = array[k+1][1];
            array[k][2] = array[k+1][2];
            array[k][3] = array[k+1][3];
            }
            array[i-1][0] = " ";
            array[i-1][1] = " ";
            array[i-1][2] = " ";
            array[i-1][3] = " ";

            i--;
            count=i;

         }
         else if (array[j][1]== "IN:")
 {
     for (int k = j; k < i; k++)
     {
        array[k][0] = array[k+1][0]; 
        array[k][1] = array[k+1][1];
        array[k][2] = array[k+1][2];
        array[k][3] = array[k+1][3];            
     }
        array[i-1][0] = " ";
        array[i-1][1] = " ";
        array[i-1][2] = " ";
        array[i-1][3] = " ";
        j++;
        i--;
 }
         else if (count=i)
         {
             j++;

         }

         else
         {
             count++;
         }

     }

 }
 else if (array[j][1]== "IN:")
 {
     for (int k = j; k < i; k++)
     {
        array[k][0] = array[k+1][0]; 
        array[k][1] = array[k+1][1];
        array[k][2] = array[k+1][2];
        array[k][3] = array[k+1][3];            
     }
        array[i-1][0] = " ";
        array[i-1][1] = " ";
        array[i-1][2] = " ";
        array[i-1][3] = " ";
        j++;
        i--;
 }

    }




    h=i;
    i=0;
    ofstream outFile;
    outFile.open("test2.rtf");
    while(h!=0){
    outFile << array[i][0] << " " << array[i][1] << " " <<array[i][2] << " "  <<array[i][3]<<endl;
    i++;
    h--;                
    }
    inFile.close();

    return 0;
    }

Any thoughts would be great cause I am running out of ideas :)

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • In general, don't do `while (!file.eof())` because the EOF flag isn't set until *after* a read operation failed. Instead do e.g. `while (inFile >> array[i][0] >> ...)` – Some programmer dude Jun 19 '13 at 15:25
  • And don't use hard-coded arrays, instead use `std::vector`. In this case maybe a `std::vector` of `std::array`? – Some programmer dude Jun 19 '13 at 15:26
  • But while (!file.eof()) works fine. I can reproduce the list perfectly when commenting out the the bulk of the program. –  Jun 19 '13 at 15:45
  • But it *doesn't* work fine, as it will loop one to many thereby increasing the index `i` to one beyond the actual data. – Some programmer dude Jun 19 '13 at 15:55
  • Good call, didn't think about that. –  Jun 19 '13 at 16:01
  • Given the basics you (apparently) still need to learn, perhaps you'd be best off starting from something in [the book list](http://stackoverflow.com/q/388242/179910). – Jerry Coffin Jun 19 '13 at 16:17
  • That is the smallest issue with the program... being off my and index of one will not solve my issue. –  Jun 19 '13 at 16:33

3 Answers3

0

I would start by converting each line of input into a logical record. Then I'd insert a record into a map for each "signed out" record, and remove the matching record for each "signed in" record. Depending on what (if anything) else you're doing, a set might be a little easier than a map.

If you have a "signed in" record for an item that's not currently signed out, you signal a problem with the input.

When you're done, write out all the items in the map (or set). Those are the ones that have been signed out but not signed back in.

Edit: code would look something like this:

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

struct record {
    std::string time;
    std::string inout;
    std::string item;
    std::string user;

    bool operator<(record const &other) const { 
        return item < other.item;
    }
};

std::istream &operator>>(std::istream &is, record &r) { 
    std::string line;
    std::getline(is, line);
    std::stringstream buffer(line);

    buffer >> r.time >> r.inout >> r.item >> r.user;
    return is;
}

std::ostream &operator<<(std::ostream &os, record const &i) { 
    return os << i.item << "\t" << i.user;
}

int main() {
    std::set<record> items;
    record temp;
    std::ifstream in("test.rtf");

    while (in >> temp) {
        if (temp.inout == "OUT:")
            items.insert(temp);
        else
            items.erase(temp);
    }

    for (auto const & i : items) 
        std::cout << i << "\n";
}
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • You kinda lost me there Jerry, I'm really only familiar is simplistic syntax in C++. –  Jun 19 '13 at 15:46
  • This looks like it could work but after testing it out it appears to have an error of about 8 items when using a longer list. Also I would like to write the time stamps and I guess the "out:" just to verify that it is picking up the right lines. I will have to try to figure out your code to find the error but otherwise this is a start :). –  Jun 19 '13 at 16:32
  • @IanFolk: the most likely problem is that it assumes the only spaces in the input are between fields. For file names (for one example) that include spaces, you'll have to work with matching quotes to get entire file names. – Jerry Coffin Jun 19 '13 at 17:18
0

I would use map and set to get what you want:

#include <iostream>
#include <string>
#include <map>
#include <set>

int main(int, char**) {
  using namespace std;

  string time, in_out, exe, user;
  map<string,int> out;

  while( cin >> time >> in_out >> exe >> user ) {
    if( in_out == "OUT:" ) 
      out[user]++;
    else
      out[user]--;
    if( out[user] == 0 )
      out.erase(user);
  }

  set<string> ordered;
  for( auto& s: out ) {
    ordered.insert(s.first);
  }
  for( auto& s: ordered ) {
    cout << s << endl;
  } 

  return 0;
} 

The output for the sample input is:

CONHorodeski@ALNWSPCNTRCTR1
mlulchak@alnsvpmillterm

(the first one logged out twice at 16:07 and 16:10 but just logged in once at 16:11 and the second one logged in at 17:49 and never logged out)

Massa
  • 8,647
  • 2
  • 25
  • 26
  • Working with this a little, it appears to filter through the list but it isn't keeping the correct lines. Could you explain your elimination process? –  Jun 19 '13 at 17:13
  • if the program sees `OUT:`, it increments a counter for each user; if it sees `IN:`, it decrements it (the `if(int_out == "OUT:") out[user]++; else out[user]--;` part. then it gets the non-zero items (that logged out without having logged back in or vice-versa) and prints them, in order (that's what the `set` is for). I edited the answer to show the output and the reason for it. – Massa Jun 19 '13 at 18:01
0

Take a look at this solution for your problem, I suggest to you to use stl sort algorithm for sort the output and struct for store data.

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

#define MAX 1005

struct record{
    string A,B,C,D;
    record(string A, string B, string C, string D) :
        A(A), B(B), C(C), D(D) {}

    bool operator < (const record& o) const
    {
        string tmp1 = A + " " + B + " " + C + " " + D;
        string tmp2 = o.A + " " + o.B + " " + o.C + " " + o.D;
        return (tmp1 < tmp2);
    }
};

int main() {
    string A,B,C,D;
    vector<record> my_vect;
    vector<record>::iterator it;

    ifstream inFile;
    inFile.open("test1.rtf");

    while(inFile >> A >> B >> C >> D) {
        if(B == "OUT:")
            my_vect .push_back( record(A,B,C,D) );
    }

    inFile.close();

    sort(my_vect.begin(), my_vect.end());

    ofstream outFile;
    outFile.open("test2.rtf");
    for(it = my_vect.begin(); it != my_vect.end(); ++it) {
        outFile << (*it).A << " " << (*it).B << " " << (*it).C << " " << (*it).D << endl;
    }
    outFile.close();

    return 0;
}

The output for this algo is:

15:39:32 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
15:40:10 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
15:40:31 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
15:47:10 OUT: "RS5K_700.EXE" SYSTEM@ALNWSPCNTRCTR1
16:07:48 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
16:10:15 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
17:01:49 OUT: "RS500.EXE" mlulchak@alnsvpmillterm
9:30:28 OUT: "RS5K_700.EXE" CONHorodeski@ALNWSPCNTRCTR1
Luis Daniel
  • 687
  • 7
  • 18
  • Is not necesary to use map, because with this you get an innecesary complexity of O(log n) for inserting and getting data every time. You just need to sort the correctly list once using the sort algorithm from stl. – Luis Daniel Jun 19 '13 at 16:28
  • It looks like you just wrote all the 'sign outs' to a file. I need to eliminate all 'OUTS:' that have a matching 'IN:' –  Jun 19 '13 at 16:28