C++ Readfile/Parse it - change tokens

Hi Folks,

I am trying to write a code in C++ which should open a text file, store the lines in to an array (each line in to an element) and change some of the tokens (see below for an example). The file is in three parts as a header, body and footer.

File content:

15_Date_20060212 //Header starts here
14_Time_1:21am
13_Day_Sunday
10_Name_Nick //Body starts here
9_Age_22
8_SS_999-99-9999
7_quantity_1
10_Name_Jen
9_Age_21
8_SS_999-99-9999
7_quantity_1
10_Name_Chealse
9_Age_19
8_SS_999-99-9999
7_quantity_1
10_Name_Justin
9_Age_24
8_SS_999-99-9999
7_quantity_1
10_Name_Ching
9_Age_20
8_SS_999-99-9999
7_quantity_1
6_Enddate_20060212 //Footer starts here
5_Endtime_1:59am
4_Endday_sunday

The main objective of this code is to change quantity from 1 to as many name are there - so in this case there are five names so it should change from 1 to (1,2,3,4,5 for each name respectively) (the body content is not defined it could be 1 or it could be 1000) Header and footer remians the same..

Please help me guys or tell me where i can start.

Thanks alot for you help

Nick
[1233 byte] By [nkapachi] at [2007-11-19 18:30:07]
# 1 Re: C++ Readfile/Parse it - change tokens
So where is exactly the problem? With reading the file? With changing the tokens? :confused:

Can you post the code you have written so far?

Cheers
golanshahar at 2007-11-10 23:46:40 >
# 2 Re: C++ Readfile/Parse it - change tokens
Following is the code i have written so far...

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

int
main()
{
std::cout << "Enter filename: ";

std::string filename;

cin >> filename;

std::ifstream file(filename.c_str());

if(!file)
{
std::cerr << "Error opening file " << filename << std::endl;

return EXIT_FAILURE;
}

std::string line;
std::vector<std::string> contents_of_file;

while(getline(file, line))
{
contents_of_file.push_back(line);

std::cout << "Read line " << line << std::endl;
}

std::cout << "Read " << contents_of_file.size() << " lines from the file." << std::endl;
std::cout << "Any particular line is accessed using contents_of_file[line_number-1]."
<< std::endl;

}

now the problem here is how can i parse this vector in to tokens and changes the quantity from 1 to (1,2,3,4,5)

thanks alot for your help

Nick
nkapachi at 2007-11-10 23:47:40 >
# 3 Re: C++ Readfile/Parse it - change tokens
making some assumptions about your files

std::string CreateQuantityString(unsigned int count)
{
std::ostringstream oss;
oss << "7_quantity_" << count;
return oss.str();
};

unsigned int count(1);
for(size_t i = 0; i < contents_of_file.size(); i++)
{
if(!contents_of_file[i].empty() && '7' == contents_of_file[i][0])
{
contents_of_file[i] = CreateQuantityString(count);
count++;
}
}
souldog at 2007-11-10 23:48:36 >
# 4 Re: C++ Readfile/Parse it - change tokens
thanks - souldog

Question - Will this output to the file?

Thanks!
nkapachi at 2007-11-10 23:49:41 >
# 5 Re: C++ Readfile/Parse it - change tokens
then how can i get updated file (quantity changed to 1,2,3,4,5..)

thanks
nkapachi at 2007-11-10 23:51:46 >
# 6 Re: C++ Readfile/Parse it - change tokens
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>

std::string CreateQuantityString(unsigned int count)
{
std::ostringstream oss;
oss << "7_quantity_" << count;
return oss.str();
};

int main()
{
std::cout << "Enter filename: ";

std::string filename;

cin >> filename;

std::ifstream file(filename.c_str(), std::ios::in | std::ios::out);
std::ostream out(file.rdbuf());

if(!file)
{
std::cerr << "Error opening file " << filename << std::endl;

return EXIT_FAILURE;
}

std::string line;
std::vector<std::string> contents_of_file;

while(getline(file, line))
{
contents_of_file.push_back(line);

std::cout << "Read line " << line << std::endl;
}

std::cout << "Read " << contents_of_file.size() << " lines from the file." << std::endl;
std::cout << "Any particular line is accessed using contents_of_file[line_number-1]."
<< std::endl;

out.seekp(0);

unsigned int count(1);
for(size_t i = 0; i < contents_of_file.size(); i++)
{
if(!contents_of_file[i].empty() && '7' == contents_of_file[i][0])
{
contents_of_file[i] = CreateQuantityString(count);
count++;
}

out << contents_of_file[i] << '\n';
}

}
souldog at 2007-11-10 23:52:45 >
# 7 Re: C++ Readfile/Parse it - change tokens
Thanks alot souldog...

I will try this asap and let you know.

Thanks again!

Nick
nkapachi at 2007-11-10 23:53:43 >
# 8 Re: C++ Readfile/Parse it - change tokens
Souldog - The code works great

However i am face just a minor issue

what if i have '7' more than once for example right now we have "7_qantity_1" but i may also have "7_status_single"

so the input file could contain (more then one 7 character)

Forexample:
15_Date_20060212 //Header starts here
14_Time_1:21am
13_Day_Sunday
10_Name_Nick //Body starts here
9_Age_22
8_SS_999-99-9999
7_quantity_1
7_status_single
10_Name_Jen
9_Age_21
8_SS_999-99-9999
7_quantity_1
10_Name_Chealse
9_Age_19
8_SS_999-99-9999
7_quantity_1
7_status_married
10_Name_Justin
9_Age_24
8_SS_999-99-9999
7_quantity_1
10_Name_Ching
9_Age_20
8_SS_999-99-9999
7_quantity_1
7_status_single
6_Enddate_20060212 //Footer starts here
5_Endtime_1:59am
4_Endday_sunday

Sorry for this not being cleared..

Thanks for your help..

Nick
nkapachi at 2007-11-10 23:54:47 >
# 9 Re: C++ Readfile/Parse it - change tokens
well you need to change the criterion on which you determine if a line is a
"quantity" line. Whatever makes these lines unique from the others

one possiblility

const std::string quantity = "quantity";

change the criterion from

if(!contents_of_file[i].empty() && '7' == contents_of_file[i][0])

to

if(string::npos != contents_of_file[i].find(quantity))
souldog at 2007-11-10 23:55:49 >
# 10 Re: C++ Readfile/Parse it - change tokens
Yeah that would work great or i have made changes to something similar to the following. (just trying to make the comparision unique here..)

if(!contents_of_file[i].empty() && '7' == contents_of_file[i][0] && 'q' == contents_of_file[i][2])

Thanks for all your help souldog - you have been a great help!...
nkapachi at 2007-11-10 23:56:50 >
# 11 Re: C++ Readfile/Parse it - change tokens
just for learning, go into your file and change one of the lines

7_quantitiy_1

to read

7_

and the run you program. It will crash. You should protect against things like that.

with

if(!contents_of_file[i].empty() && '7' == contents_of_file[i][0] )

it was ok, since the string not being empty implies that there is at least one character. You should note, that && statements like the above are evaluated
from left to right and if one of the conditions fails, the remaining ones are not
evaluated.

So if the string is in fact empty, '7' == contents_of_file[i][0] is not checked.

In your case you need to change !contents_of_file[i].empty() to something
that guarantees there are at least 3 characters in the string. So

if(3 <= contents_of_file[i].length() && ...)
souldog at 2007-11-10 23:57:45 >
# 12 Re: C++ Readfile/Parse it - change tokens
yeah that is a very valuable point...

Never thought of it since i am a EE not CS...

Thanks again for pointing that out very clearly..

Now that i have a working algorithm i would like to paste this in my dll, so all i need to do is take out all the "cout<<" right?

I will paste my logic for you to look at it by tomorrow

Thanks again!
nkapachi at 2007-11-10 23:58:49 >
# 13 Re: C++ Readfile/Parse it - change tokens
Hi

I have made changes (just few - took out all the couts, hard coded the file location and added "g_oLogFile.Log("Read line %s",line);" in the while loop to log what am i reading) to make it work with my dll (see below)

string filename = "C:\Documents and Settings\UnigenAdm\Desktop\CreateDirectoryTest";

std::ifstream file(filename.c_str(), std::ios::in | std::ios::out);
std::ostream out(file.rdbuf());

if(!file)
{
std::cerr << "Error opening file " << filename << std::endl;

return EXIT_FAILURE;
}

std::string line;
std::vector<std::string> contents_of_file;

while(getline(file, line))
{
contents_of_file.push_back(line);
g_oLogFile.Log("Read line %s",line);
}

out.seekp(0);

unsigned int count(1);
for(size_t i = 0; i < contents_of_file.size(); i++)
{
if(!contents_of_file[i].empty() && '3' == contents_of_file[i][0] && 'p' == contents_of_file[i][2] && 't' == contents_of_file[i][4])
{
contents_of_file[i] = CreateQuantityString(count);
count++;
}

out << contents_of_file[i] << '\n';
}

02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z
02/14/06 09:12:27 Read line r@D@2@@std@@AAEX_N@Z

Totat like count is 36 and thats what i have in the original file...

now the problem is why does it work with the regular compile/run but not with the dll, what is this "r@D@2@@std@@AAEX_N@Z"??)

Thanks for your help...

Nick
nkapachi at 2007-11-10 23:59:49 >
# 14 Re: C++ Readfile/Parse it - change tokens
I think i have fixed the other issue (the one i was facing this morning)... however now i am looking at the bigger problem... like i mentioned before - the file which we are opening may contain more than 4000 lines..
so to read these lines in to a vector and change the tokens, it would take some good amount of time..

Now the problem is - I am running a xeon 3.2ghz ( i belive it is hypre-threading/2x or 4x core) processor. Since the changing tokens would take good amount of time.. the code after the "for-loop" started to execute while the token is being change.. (i am guessing because of hyper-threading)

CString Target_location;
Target_location = pDir + "\\" + "data\\datalog\\" + ID + "\\" + "test.txt";
string filename;
filename = (string)Target_location;

std::ifstream file(filename.c_str(), std::ios::in | std::ios::out);
std::ostream out(file.rdbuf());
if(!file)
{
std::cerr << "Error opening file " << filename << std::endl;
return EXIT_FAILURE;
}

std::string line;
std::vector<std::string> contents_of_file;
while(getline(file, line))
{
contents_of_file.push_back(line);
}

out.seekp(0);
unsigned int count(1);
for(size_t i = 0; i < contents_of_file.size(); i++)
{
if(!contents_of_file[i].empty() && '3' == contents_of_file[i][0] && 'p' == contents_of_file[i][2] && 't' == contents_of_file[i][4])
{
contents_of_file[i] = CreateQuantityString(count);
count++;
}
out << contents_of_file[i] << '\n';
}


//************ Sleep for 5secs before entering in the shared rollup algorithm ************//

Sleep(5000);

CopyResults(ID,pDir); //(this function copies the file to a network drive)

How can i make the changing tokens (for-loop) a thread-lock (thread-safe,mutex,..)

so that the next line (code - function copies to a network drive) would wait till its done changning the token..

Souldog - Please help me resolve this issue, i have been fighthing all day to resolve it but found nothing...Thanks alot for your help,

Nick
nkapachi at 2007-11-11 0:00:51 >
# 15 Re: C++ Readfile/Parse it - change tokens
so your application is multithreaded? Hyperthreading has nothing to do with
this.

I will need to know some more about how your application works.
How this function is being called.
souldog at 2007-11-11 0:01:49 >
# 16 Re: C++ Readfile/Parse it - change tokens
Yeah Souldog you were rigth Hyper-Threading got nothing to do with this...

I just added file.close() before it calls - copies to the shared drive function and it worked fine...

This is awesome!

Thanks a million...
nkapachi at 2007-11-11 0:02:53 >