C++ Splitting the input problem - c++

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

Related

Why splitting a line separated by spaces with stream in C++ runs infinitely?

Before, when I was writing C++, I often used getch() for validation. However, now I am turning into competitive programming, I cannot use getch(); I had to use cin or getline. Thus, today, I replicated an instance of splitting a string using stringstream:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main() {
string line;
getline(cin, line);
cout << line << endl;
stringstream reader;
reader.clear();
reader.str(line);
vector<long long int> list;
while (true) {
reader.clear();
if (reader.str().size() == 0) {
break;
}
long long int value;
reader >> value;
list.push_back(value);
}
}
Then, I ran the program, typed 1 2 3 4 5 6 7 8 9 and pressed enter. The program successfully displayed line, 1 2 3 4 5 6 7 8 9, but the program just didn't terminate. It never approached the end of the main() function. I tried to print reader.str(), but it just print 1 2 3 4 5 6 7 8 9 continually. I was confused. Why reader >> value didn't run and did not read any value? Why was the program running an infinite loop? How can I fix the issue? I appreciate any solution.
The reading operator >> does not change the underlying string. It uses an inner position of a next char to read.
int main() {
int n;
std::istringstream in; // could also use in("1 2")
in.str("1 2");
in >> n;
std::cout << "after reading the first int from \"1 2\", the int is "
<< n << ", str() = \"" << in.str() << "\"\n";
}
Outputs
after reading the first int from "1 2", the int is 1, str() = "1 2"
The loop may be terminated by replacing reader >> value; with
if (!(reader >> value))
break;
... but the program just didn't terminate.
This means that ...
while (true)
true is never false, or ...
reader.str().size() == 0
is never true.
true, in fact, is never false, and you never change the size of the reader's string object. Why would you expect this loop to break?
Please edit your question to make it more clear what you are trying to accomplish.

Read a file line by line with specific data 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

Reading from file returns a result I didn't expect, trying to understand why

I have this code which contains a class and a main function:
class Employee {
int m_id;
string m_name;
int m_age; public:
Employee(int id, string name, int age) :m_id(id), m_name(name), m_age(age) {}
friend ostream& operator<<(ostream& os, const Employee& emp)
{
os << emp.m_id << " " << emp.m_name << " " << emp.m_age
<< endl;
return os;
}
};
int main() {
const int Emp_Num = 3;
fstream fs("dataBase.txt", ios::out);
if (!fs) {
cerr << "Failed opening file. Aborting.\n";
return -1;
}
Employee* list[Emp_Num] =
{ new Employee(1234, "Avi", 34),
new Employee(11111, "Beni", 24),
new Employee(5621, "Reut", 26) };
for (int i = 0; i < Emp_Num; i++)
{
fs << (*list[i]);
delete list[i];
}
fs.close();
fs.open("dataBase.txt");
if (!fs) {
cerr << "Failed opening file. Aborting.\n";
return -1;
}
fs.seekg(4);
string strRead;
fs >> strRead;
cout << strRead << endl;
fs.seekg(6, ios::cur);
fs >> strRead;
cout << strRead << endl;
fs.seekg(-9, ios::end);
fs >> strRead;
cout << strRead << endl;
}
Here is how I understand it, after the first file open and close, the file dataBase.txt should look like this:
1234 Avi 34
11111 Beni 24
5621 Reut 26
My problem is with the reading and output to the console.
After I open the file, the pointer of my current position is at the first byte, which is the 1 before the 1234.
I seek 4 from the beginning of the file,
so my pointer should be at (before) the space between the 1234 and Avi.
Now I get the next string into my string variable strRead,
now strRead contains "Avi" and the pointer should be between the i of Avi and the space after it.
Now i seek 6 from my current position,
by my count those are the 6 bytes i pass through:
Space
3
4
Line break (return)
1
1
So my pointer should be at the second line, after the two first ones.
I mean like this:
11|111 Beni 24
Now I get a string to strRead, by my understanding of the code strRead should now contain "111", instead, for some reason, it contains and output later "1111".
Could someone explain me why does it work that way?
There is no character between the first line drop and the first letter of the second line, so it should count as only 1 byte...
I did the following test:
I have run the second part of your code (which read from file) on a file with the text:
1234 Avi 34 11111 Beni 24 5621 Reut 26
So, I have replaced end of lines with spaces, and the code print to console output the expected result 111. I then began to be suspicious about seek skipping end of lines.
Then I changed the code instead (without file modifications) and worked with the file in binary mode:
//...
fstream fs("dataBase.txt", ios::out | ios::binary);
//...
fs.open("dataBase.txt", ios::in | ios::binary );
//...
Again the result was the expected: 111.
What change in both cases?
Well, in plain text (not in binary mode) the end of line are actually 2 chars (this can vary for other platforms, I'm reproducing this on Windows): \r and \n. Thats why you're reading four ones (1111) instead three (111).
Counting 6 positions from the space after Avi:
A v i _ 3 4 \r \n 1 1 1 1 1
^
1 2 3 4 5 6 7 8
In the first test I performed, the a space (only one character) replaced two of them.
A v i _ 3 4 _ 1 1 1 1 1
^
1 2 3 4 5 6 7 8
And in binary mode both of characters are represented as a single one unit to read(I don't have investigated if this is platform dependant).
A v i _ 3 4 B 1 1 1 1 1
^
1 2 3 4 5 6 7 8
B stands here for some binary code.

How to parse a part of a string, which have characters other than digits, to integer

I am currently trying to read information from an .txt file and essentially store this appropriately. Data from the input file would look something like this
10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
765DEF 01:01:05:59 enter 17
ABC123 01:01:06:01 enter 17
765DEF 01:01:07:00 exit 95
ABC123 01:01:08:03 exit 95
My question is that, assuming I have read "01:01:05:59" into a string, how do I parse this to store the numbers in an int variable. In addition, all I really need is the third pair of numbers in that string(from the left) and I was also wondering how to skip the first two and last pair of numbers in that string. I have read on delimiters but I'm a little confused on how to use them. The code I have so far is shown below and is basically that information to strings.
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
int arr[25];
ifstream File;
File.open("input.txt");
for (int a = 0; a < 25; a++)
{
File >> arr[a];
}
for (int i = 0; i < 25; i++)
{
cout << arr[i] << " ";
}
cout << endl;
string license, datetime;
File >> license >> datetime; // reads in license plate and datetime information into two separte strings
cout << license << endl << datetime;
system("pause");
}
Background:
If we know the start and end indices (or the length) of the sub-string we need, then we can read it by using std::string::substr.
Its usage is as follows:
#include <string>
...
std::string foo = "0123456789stack:overflow";
// start index = 4, length = 2
std::string subStr1 = foo.substr(4,2); // result = "45"
// start index = 3, end index = 5 => length = 5 - 3 + 1 = 3
std::string subStr2 = foo.substr(3,3); // result = "345"
// The first parameter is the start index whereas the second one is
// the length of the wanted sub-string.
// If only the start index is known:
std::string subStr2 = foo.substr(9); // result = "9stack:overflow"
// In that case we get the rest of the string starting from the start index 9.
For more information on that please refer to: http://www.cplusplus.com/reference/string/string/substr/
Suggested solution to the OP:
Since you said "all I really need is the third pair of numbers" then you need two characters starting from index 6:
std::string a = "01:01:05:59";
std::string sub = a.substr(6, 2); // will give you "05"
then convert them using:
int number = std::stoi(sub);
These steps can be shortened to:
int number = std::stoi( a.substr(6, 2) );
Further references:
First part: http://en.cppreference.com/w/cpp/string/basic_string/substr
Second part: How to parse a string to an int in C++?
PS: if you want to use character array instead of std::string then you just can get the characters with their corresponding indices. For example: i = 6 and i = 7 in your specific case. Then, get yourArray[6]=0 and yourArray[7]=5. Then perform integer conversion on them.
Could you do:
int num = std::stoi(string.substr(6, 2);
assuming I have read "01:01:05:59" into a string
One easy way is using streams:
#include <iostream>
#include <sstream>
int main()
{
int n[4];
std::istringstream iss("02:30:41:28");
if (iss >> n[0] && iss.get() == ':' &&
iss >> n[1] && iss.get() == ':' &&
iss >> n[2] && iss.get() == ':' &&
iss >> n[3] >> std::ws && iss.eof())
std::cout << n[0] << ' ' << n[1] << ' ' << n[2] << ' ' << n[3] << '\n';
else
std::cerr << "parsing error\n";
}
On ideone.com

Read from string into stringstream

When I try to parse whitespace seperated double values from a string, I found this curious behaviour that the string is read out in a cyclic manner.
Here's the program:
stringstream ss;
string s("1 2 3 4");
double t;
list<double> lis;
for(int j=0; j!=10; ++j){
ss << s;
ss >> t;
lis.push_back(t);
}
for(auto e : lis){
cout << e << " ";
}
Here the output:
1 2 3 41 2 3 41 2 3 41
If I append a trailing space as s= "1 2 3 4 "; I get
1 2 3 4 1 2 3 4 1 2
Now the questions:
1) If I don't know how many entries are in the string s, how do I read all into the list l?
2) which operator<< am I actually calling in ss << s;? Is it specified to read circularly?
3) Can I do the parsing in a better way?
Thanks already!
Here's the fixed code (thanks to timrau):
// declarations as before
ss << s;
while(ss >> t){
lis.push_back(t);
}
// output as before
This produces:
1 2 3 4
as desired. (Don't forget to clear your stringstream by ss.clear() before treating the next input. ;))
Another useful comment from HeywoodFloyd: One could also use boost/tokenizer to "split" the string, see this post
You can test the return value of >>.
while (ss >> t) {
lis.push_back(t);
}
It's not specified to read circularly. It's ss << s appending "1 2 3 4" to the end of the stream.
Before the 1st loop:
""
After 1st ss << s:
"1 2 3 4"
After 1st ss >> t:
" 2 3 4"
After 2nd ss << s:
" 2 3 41 2 3 4"
Then it's clear why you get 1 2 3 41 2 3 41 2 3 41 if there is no trailing space in s.
then use s.length() for strings containing unknown number of entries, if you use your approach.
Or, as suggested by timrau, just initialize your stringstream once.
stringstream ss;
string s("1 2 3 4 5 6 7 8");
ss << s;
double t;
list<double> lis;
while (ss >> t) {
lis.push_back(t);
}
for(auto e : lis){
cout << e << " ";
}
This stackoverflow post includes a boost tokenizer example. You may want to tokenize your string and iterate through it that way. That will solve the no trailing space problem timrau pointed out.