Read a file line by line with specific data C++ - c++

I have a file with this format:
11
1 0
2 8 0
3 8 0
4 5 10 0
5 8 0
6 1 3 0
7 5 0
8 11 0
9 6 0
10 5 7 0
11 0
The first line is the number of lines, so I can make a loop to read the file with the number of lines.
For the other lines, I would like to read the file line by line and store the data until I get a "0" on the line that's why there is a 0 at the end of each line.
The first column is the task name.
The others columns are the constraints name.
I tried to code something but It doesn't seem to work
printf("Constraints :\n");
for (int t = 1; t <= numberofTasks; t++)
{
F >> currentTask;
printf("%c\t", currentTask);
F >> currentConstraint;
while (currentConstraint != '0')
{
printf("%c", currentConstraint);
F >> currentConstraint;
};
printf("\n");
};
The "0" represents the end of the constraints for a task.
I think my code doesn't work properly because the constraint 10 for the task 4 contains a "0" too.
Thanks in advance for your help
Regards

The problem is that you are reading individual characters from the file, not reading whole integers, or even line-by-line. Change your currentTask and currentConstraint variables to int instead of char, and use std::getline() to read lines that you then read integers from.
Try this:
F >> numberofTasks;
F.ignore();
std::cout << "Constraints :" << std::endl;
for (int t = 1; t <= numberofTasks; ++t)
{
std::string line;
if (!std::getline(F, line)) break;
std::istringstream iss(line);
iss >> currentTask;
std::cout << currentTask << "\t";
while ((iss >> currentConstraint) && (currentConstraint != 0))
{
std::cout << currentConstraint << " ";
}
std::cout << std::endl;
}
Live Demo
That being said, the terminating 0 on each line is unnecessary. std::getline() will stop reading when it reaches the end of a line, and operator>> will stop reading when it reaches the end of the stream.
Live Demo

Related

Behaviour of fstream in C++

I have made the following script, that is supposed to read from a file:
char match[] = "match";
int a;
int b;
inp >> lin;
while(!inp.eof()) {
if(!strcmp(lin, match)) {
inp >> a >> b;
cout << a << " " << b <<endl;
}
inp >> lin;
}
inp.close();
return num_atm;
}
It is supposed to read all words, and if a line starts with match, it should then also print the rest of the line.
My input file is this:
match 1 2 //1
match 5 2 //2
nope 3 6 //3
match 5 //4
match 1 4 //5
match 5 9 //6
It will correctly print 1 2, 5 2, and skip 3 6. But then, it will get stuck and keep printing 5 0 and continue printing 5 0 for ever. I get that match is put into b, which is an integer, but I don't get why this is looped. Shouldn't the input read match 4 once, try to read/write 5 and match, and then be done with line 4 and the match from line 5? Then it should next read the number 1 and 4 and then match from number 6.
I would also understand that due to the word not fitting into the integer, it would read match in the fifth line again, but that's not what it does.
It goes back to the match in the fourth line which it already read, and reads it again. Why is this?
When you are reading with >> line enndings are handled the same as spaces: They are just more whitespace that is skipped. That means you see
match 1 2
match 5 2
nope 3 6
match 5
match 1 4
match 5 9
But the program sees
match 1 2 match 5 2 nope 3 6 match 5 match 1 4 match 5 9
Let's fast forward to where things go south
Contents of stream:
nope 3 6 match 5 match 1 4 match 5 9
Processing
inp >> lin; // reads nope stream: 3 6 match 5 match 1 4 match 5 9
if(!strcmp(lin, match)) { // nope != match skip body
}
inp >> lin; // reads 3 stream: 6 match 5 match 1 4 match 5 9
if(!strcmp(lin, match)) { // 3 != match skip body
}
inp >> lin; // reads 6 stream: match 5 match 1 4 match 5 9
if(!strcmp(lin, match)) { // 6 != match skip body
}
inp >> lin; // reads match stream: 5 match 1 4 match 5 9
if(!strcmp(lin, match)) { // match != match Enter body
inp >> a >> b; // reads 5 and fails to parse match into an integer.
// stream: match 1 4 match 5 9
// stream now in failure state
cout << a << " " << b <<endl; // prints 5 and garbage because b was not read
}
inp >> lin; // reads nothing. Stream failed
if(!strcmp(lin, match)) { // match != match Enter body
inp >> a >> b; // reads nothing. Stream failed
// stream: match 1 4 match 5 9
// stream now in failure state
cout << a << " " << b <<endl; // prints g and garbage because b was not read
}
Because nothing is ever read, while(!inp.eof()) is utterly worthless. The end of the file can never be reached. The program will loop forever, probably printing whatever it last read. Successfully read.
Fixing this depends entirely on what you want to do if you have a match line without 2 numbers on it, but a typical framework looks something like
std::string line;
while(std::getline(inp, line) // get a whole line. Exit if line can't be read for any reason.
{
std::istringstream strm(line);
std::string lin;
if(strm >> lin && lin == match) // enters if lin was read and lin == match
// if lin can't be read, it doesn't matter.
// strm is disposable
{
int a;
int b;
if (strm >> a >> b) // enters if both a and b were read
{
cout << a << " " << b <<"\n"; // endl flushes. Very expensive. just use a newline.
}
}
}
Output from this should be something like
1 2
5 2
1 4
5 9
If you want to make some use of match 5... Well it's up to you what you want to put in b if there is no b in the file.

How to read sequences with spaces and stop when the user presses "enter" in C++?

As title, I am a beginner in learning C++.
I want to read several sequences(s1,s2,s3...) containing integers seperated by spaces into an array,and stop reading s1 to read s2 by pressing "enter".
#
Here's the test data:
4 9 6 6
1 2 3 4
3 3 5 6 9 15 18 15 18 30 3 3 5 6 9 15 18 15 18 30 1 9 9 25 36
The result I expect would be :
arr[0]={4,9,6,6}
arr[1]={1,2,3,4}
arr[2]={3,3,5,6,9,15,18,15,18,30,3,3,5,6,9,15,18,15,18,30,1,9,9,25,36}
#
I used a time consuming way to read data into my array:
while(1){
int i=0,j=0;
int arr[100][25];
char test;
while(1){
stringstream ss;
cin.get(test);
if(test==' '){
ss<<seq;
seq.clear();
ss>>arr[i][j];
j++;
continue;
}
else if(test=='\n'){
ss<<seq;
seq.clear();
ss>>arr[i][j];
i++;
j=0;
break;
}
else{
seq=seq+test;
}
}
}
Online Judge will show "TLE" when the program reads big integers.
I know that break down integers into characters is a time consuming work,
what can I do with my program?
One way to do this could be using strings. The example below, based on this answer, reads each line in a string, and splits it by space. It will work only if the numbers are split by single spaces. The split numbers are stored in a vector of strings in the example, and can be converted to int using stoi.
string nums;
while(getline(cin,nums)) {
istringstream iss(nums);
vector<string> tokens;
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(tokens));
// print what is added
for(int i = 0; i < tokens.size(); i++) {
cout << tokens[i] << " ";
}
cout << endl;
}

Counting consecutive number of times in C++?

I am learning C++ to write a program to count how many consecutive times each distinct value appears in the input.
The code is
#include <iostream>
int main()
{
// currVal is the number we're counting; we'll read new values into val
int currVal = 0, val = 0;
// read first number and ensure that we have data to process
if (std::cin >> currVal)
{
int cnt = 1; // store the count for the current value we're processing
while (std::cin >> val)
{ // read the remaining numbers
if (val == currVal) // if the values are the same
++cnt; // add 1 to cnt
else
{ // otherwise, print the count for the previous value
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
currVal = val; // remember the new value
cnt = 1; // reset the counter
}
} // while loop ends here
// remember to print the count for the last value in the file
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
} // outermost if statement ends here
return 0;
}
But it won't count the last set of numbers. For example: If I have input 5 5 5 3 3 4 4 4 4, the output is:
5 occurs 5 times.
3 occurs 2 times.
The last set result which is "4 occurs 4 times." does not show up.
I wonder what is wrong with the code.
Please help.
Thanks.
hc.
Your program is correct. Your while loop will exit when the condition is false
while (std::cin >> val)
The stream input will return false when you reach end of file (EOF), which from a terminal you can enter with Ctrl-D.
Try placing your input in a file, and your program will work. I've used the cat command to copy from the terminal's standard input and redirected to a file called input. You need to press Ctrd-D to tell cat that you are done. You could also create the input file using your favorite editor.
$ cat > input
5 5 5 3 3 4 4 4 4
<press Ctrl-D here>
Now invoke the program and redirect input from the file
$ ./test < input
Output is
5 occurs 3 times
3 occurs 2 times
4 occurs 4 times
See this related question on SO
the question on while (cin >> )
You seem to generate output only when (val == currVal) is false. What makes you think this will happen after the last 4 is read from input?

Assign last number of a text file to a variable C++

I am doing a program that outputs a list of prime numbers with fstream.
I have this so far:
int export_list (int lim = 50)
{
int x;
last_in_txt = ????????????; // assigns last number on txt
ofstream file ("Primes.txt" , ios::app);
if (file.is_open()) // if it opens correctly
{
for (x = last_in_txt ; x < lim ; x++)
{
if (check_prime (x)) // returns 1 when x is prime, returns 0 when not
{
file<< x << " ";
}
}
cout << "Done!" << endl << pressenter;
cin.get();
}
else
{
cout << "Unable to open file" << endl << pressenter;
cin.get();
}
return(0);
}
So, as you can see, this should append a list of prime numbers to Primes.txt, starting with the prime 1234547.
Primes.txt looks like this:
2 3 5 7 11 13 17 19 23 29 31 37 (...) 1234543 1234547
My question is how do I assign 1234547 (which is the last number of the txt) to the variable last_in_txt?
Other (not so important) question:
Should I save the numbers the way I'm currently doing, or should I store each number in a separate line?
One simple way: keep reading and assign until the whole file is read.
For example,
int last_in_txt = 0;
{
ifstream infile("Prime.txt");
int k;
while(infile >> k) {
last_in_txt = k;
}
}
// Now last_in_txt is assigned properly, and Prime.txt is closed
This works well no matter the numbers in Prime.txt are separated by space characters (' ') or by newline characters ('\n').
My suggestion is that you write using binary format into the text file(using wb in C). In this case you will know how many bytes does the last number occupy and you will be able to use seekg and tellg to get it. If you use plain text format you will have to read char by char from the end and this is more error-prone and also slower.

C++ Splitting the input problem

I am being given input in the form of:
(8,7,15)
(0,0,1) (0,3,2) (0,6,3)
(1,0,4) (1,1,5)
(2,1,6) (2,2,7) (2,5,8)
(3,0,9) (3,3,10) (3,4,11) (3,5,12)
(4,1,13) (4,4,14)
(7,6,15)
where I have to remember the amount of triples there are. I wrote a quick testing program to try read the input from cin and then split string up to get the numbers out of the input. The program doesn't seem to read all the lines, it stops after (1,1,5) and prints out a random 7 afterwards
I created this quick testing function for one of the functions I am trying to create for my assignment:
int main ()
{
string line;
char * parse;
while (getline(cin, line)) {
char * writable = new char[line.size() + 1];
copy (line.begin(), line.end(), writable);
parse = strtok (writable," (,)");
while (parse != NULL)
{
cout << parse << endl;
parse = strtok (NULL," (,)");
cout << parse << endl;
parse = strtok (NULL," (,)");
cout << parse << endl;
parse = strtok (NULL," (,)");
}
}
return 0;
}
Can someone help me fix my code or give me a working sample?
You can use this simple function:
istream& read3(int& a, int& b, int& c, istream& stream = cin) {
stream.ignore(INT_MAX, '(');
stream >> a;
stream.ignore(INT_MAX, ',');
stream >> b;
stream.ignore(INT_MAX, ',');
stream >> c;
stream.ignore(INT_MAX, ')');
return stream;
}
It expects the stream to start at a (, so it skips any characters and stops after the first ( it sees. It reads in an int into a which is passed by reference (so the outside a is affected by this) and then reads up to and skips the first comma it sees. Wash, rinse, repeat. Then after reading the third int in, it skips the closing ), so it is ready to do it again.
It also returns an istream& which has operator bool overloaded to return false when the stream is at its end, which is what breaks the while loop in the example.
You use it like this:
// don't forget the appropriate headers...
#include <iostream>
#include <sstream>
#include <string>
int a, b, c;
while (read3(a, b, c)) {
cout << a << ' ' << b << ' ' << c << endl;
}
That prints:
8 7 15
0 0 1
0 3 2
0 6 3
1 0 4
1 1 5
2 1 6
2 2 7
2 5 8
3 0 9
3 3 10
3 4 11
3 5 12
4 1 13
4 4 14
7 6 15
When you give it your input.
Because this is an assignment, I leave it to you to add error handling, etc.
I've written a blog 9 days back exactly to parse such inputs:
Playing around with Boost.Spirit - Parsing integer triplets
And you can see the output here for your input : http://ideone.com/qr4DA