Need theory help with reading file and stuff - c++

i would like to request some help on theory part, so grind those gears, here it comes
I want to load a file into my program, which looks something like this:
0,10,10#0,100,40...
Okay what i now want to do is to take out every comma separated number and send it through my function
void func( int, float, float );
The hashtag means it's a new block, so it would be sent like func(0,10,10) and after that it would send func(0,100,40) and so on.
I was thinking to check every char until i meet ',' and after that put it in a vector, and continue that until the '#' is met. Then it would fire away my function (like func(v[0],v[1],v[2]) and then just do the same thing over and over until EOF!
Is this a good way to go? Have any better ideas? Those numbers can also get very large later on, so i don't know how much memory i need (therefor the vector). Or should i just go with 3 temp ints and floats and then fire the function and start over!

Going char by char and using a state machine like you suggested is the fastest way.
However the easiest way is first to split by the # and then for each result string split by ,.
You can use boost library to do the string split.

#include <fstream>
#include <ostream>
#include <istream>
#include <stdexcept>
void func( std::vector<float> &numbers )
{}
int main() {
std::ifstream myfile("myfile.txt");
float number;
char seperator;
std::vector<float> numbers;
while( myfile >> number) { //read number
numbers.push_back(number); //and remember it
if (!(myfile >> seperator) || seperator == "#") { //if # or EOF or error
func(numbers); //run function
numbers.clear(); //and start over
}
} //only gets here at EOF or malformed file
return 0;
}
Very simple, fast, and easy.

If you're certain the file starts with the first int of a group of three
ifstream fin("foo.csv");
string str;
stringstream s_str;
while(!fin.eof())
{
int a;
float b,c;
getline(fin,str,',');
s_str.str(str);
s_str >> a;
getline(fin,str,',');
s_str.str(str);
s_str >> b;
getline(fin,str,'#');
s_str.str(str);
s_str >> c;
}
should work. (I haven't compiled it so there might be typos etc)

Related

What's this code doing, and how can I manipulate it?

OK. It's been a long time since I've worked with C++, and I think I've got a general idea of what this code is doing. (I am taking the relevant bits of the code, assume proper libraries are pulled in, and what not.)
ifstream inFile;
inFile.open("text.txt");
int value;
while (inFile >> value)
{
while (value > 0)
{
cout << value;
}
}
inFile.close();
So, the first while function is basically searching the input file for ints, and the second one...prints it out? Or is it that if a file's input stream can't be put to an int, it leaves the value at 0? This really compact, uncommented code is...interesting.
Anyway. If I have how the above code works, I can probably figure this out on my own, but I'm here, so may as well. If I wanted to have it only print the first (variable) number of integers in a file, what would I need to do?
If I wanted to have it only print the first (variable) number of
integers in a file, what would I need to do?
#include <fstream>
#include <iostream>
int main()
{
std::ifstream inFile{ "text.txt" };
int value;
int num_values;
std::cin >> num_values;
for(int i{}; i < num_values && (inFile >> value); ++i)
cout << value;
}

counting lines from file not using getline()

I want to get some data from file and put it to variables. But before, I don't know the length of this file. File looks like:
1 12 4
2 14 5
3 26 6
. .. .
That's why I want to get a number of lines to know, how much variables I need to create in loop. In this code I created 3 variables (a,b,c) to try. The problem is that after the end of program a,b,c are just random numbers instead of 1, 12 and 4.
I noticed that if I put this:
file >> a >> b >> c;
before while loop it works, but I need number of lines earlier.
So how to count lines not using getline() ?
int a, b, c;
fstream file;
file.open("abc.txt",ios::in);
if (file.good() == true)
{
int lines_amount=0;
string test;
while (getline(file,test))
{
lines_amount++;
}
file >> a >> b >> c;
file.close();
}
When you use
while (getline(file,test))
{
lines_amount++;
}
the while loop stops only after everything from the file has been read. The line
file >> a >> b >> c;
does not read anything into a, b, or c. The values of those variables are some random values that you get since they have not been initialized before.
Initialize them to something like:
int a = 10, b = 20, c = 30;
and you will notice that:
If you use a pre-C++11 compiler, the values of those variable remain unchanged.
If you use a C++11 or later compiler, the values of those variables will be set to 0.
To be able to read the numbers from the start of the file, rewind it to the top. You can use std::ifstream::seekg for that. You have to clear its eofbit first though.
file.clear();
file.seekg(std::ifstream::beg);
What about rewinding the file indicator?
file.seekg(std::ifstream::beg);
In the previous while loop, the whole file has already been read, so there's nothing left for the next read, and a, b and c remain untouched. After this code, the file indicator is reset to the beginning of the file, so you're able to read from start again.
You may need to add file.clear() before calling seekg() to clear any flags that are already set, to prevent further operations from failing. Most of them don't do anything if a bad flag is set. In your case, when attempting to read more, the operator >> () function finds a bad flag (std::ios_base::iostate::eofbit) and stops. Further Reference
That's why i want to get a number of lines to know, how much variables i need to create in loop.
You don't need to know the number of lines beforehand. Use a std::vector to store the values, and let it grow dynamically as you add values into it. For example:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
struct values {
int a, b, c;
};
std::vector<values> data;
std::ifstream file("abc.txt");
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
std::istringstream iss(line);
values v;
if (iss >> v.a >> v.b >> v.c) {
data.push_back(v);
}
}
file.close();
// use data as needed...
}
Alternatively:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
struct values {
int a, b, c;
};
std::istream& operator>>(std::istream &in, values &v) {
std::string line;
if (std::getline(in, line)) {
std::istringstream iss(line);
if (!(iss >> v.a >> v.b >> v.c)) {
in.setstate(std::ios_base::failbit);
}
}
return in;
}
std::vector<values> data;
ifstream file("abc.txt");
if (file.is_open()) {
std::copy(
std::istream_iterator<values>(file),
std::istream_iterator<values>(),
std::back_inserter(data));
file.close();
// use data as needed...
}

How to read file with characters and integers c++

I am 90% done with a homework project of mine but this last step is kicking my butt.
I have a text file that I'm going to be reading from for my program with commands on each line.
Most of the commands are a single letter, but one of them is a letter with an integer behind it.
I ideally need to read the line, if it's just a char go right into a function I've already written for the "Command". If it has a specific character, "F" in this case, I need it to also read the integer that will be separated by a space and pass that into my other function for that command.
Example;
.txt file;
R
L
L
F 20
R
R
For those who are curious I'm mimicking the function of the Logo language that used the little "turtle" to make logo animations for my homework.
Edit
I did try researching some methods to do this but most that I came up with either grabbed just the one char, or involved strings with which I could pull each "line" but then have to read and convert what was in string to separate char and int. If that is truly the "best" way to do it I'll suck it up and do it but I wanted to see if there was something that wasn't initially obvious to me.
This would be my approach:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main() {
ifstream readFromFile("test.txt");
vector<string> fileWords;
string word;
while (readFromFile >> word) {
try {
int number = stoi(word); // here is your number
cout << number << endl;
} catch (const invalid_argument& exception) {
cout << exception.what() << endl; // just for debug
}
fileWords.emplace_back(word);
}
for (const auto& word: fileWords) {
cout << word << ' ';
}
readFromFile.close();
}
It reads word by word, saves it on an array and it also checks if a word is an integer (using the std::stoi function).
Solution by OP.
Resolved Kinda.
I ended up changing my fstream input to;
integer = 0;
char ch;
while(infile >> ch)
if (ch == "F")
{
infile >> integer;
}
// do stuff with code, I used a switch
Then after the switch I put I put integer back to 0.
This pulls the data I needed and stored it in the correct variables.

How to read space separated numbers from console?

I'm trying to do a simple task of reading space separated numbers from console into a vector<int>, but I'm not getting how to do this properly.
This is what I have done till now:
int n = 0;
vector<int> steps;
while(cin>>n)
{
steps.push_back(n);
}
However, this requires the user to press an invalid character (such as a) to break the while loop. I don't want it.
As soon as user enters numbers like 0 2 3 4 5 and presses Enter I want the loop to be broken. I tried using istream_iterator and cin.getline also, but I couldn't get it working.
I don't know how many elements user will enter, hence I'm using vector.
Please suggest the correct way to do this.
Use a getline combined with an istringstream to extract the numbers.
std::string input;
getline(cin, input);
std::istringstream iss(input);
int temp;
while(iss >> temp)
{
yourvector.push_back(temp);
}
To elaborate on jonsca's answer, here is one possibility, assuming that the user faithfully enters valid integers:
string input;
getline(cin, input);
istringstream parser(input);
vector<int> numbers;
numbers.insert(numbers.begin(),
istream_iterator<int>(parser), istream_iterator<int>());
This will correctly read and parse a valid line of integers from cin. Note that this is using the free function getline, which works with std::strings, and not istream::getline, which works with C-style strings.
This code should help you out, it reads a line to a string and then iterates over it getting out all numbers.
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string line;
std::getline(std::cin, line);
std::istringstream in(line, std::istringstream::in);
int n;
vector<int> v;
while (in >> n) {
v.push_back(n);
}
return 0;
}
Also, might be helpful to know that you can stimulate an EOF - Press 'ctrl-z' (windows only, unix-like systems use ctrl-d) in the command line, after you have finished with your inputs. Should help you when you're testing little programs like this - without having to type in an invalid character.
Prompt user after each number or take number count in advance and loop accordingly.
Not a great idea but i saw this in many applications.

C++: Check istream has non-space, non-tab, non-newline characters left without extracting chars

I am reading a std::istream and I need to verify without extracting characters that:
The stream is not "empty", i.e. that trying to read a char will not result in an fail state (solved by using peek() member function and checking fail state, then setting back to original state)
That among the characters left there is at least one which is not a space, a tab or a newline char.
The reason for this is, is that I am reading text files containing say one int per line, and sometimes there may be extra spaces / new-lines at the end of the file and this causes issues when I try get back the data from the file to a vector of int.
A peek(int n) would probably do what I need but I am stuck with its implementation.
I know I could just read istream like:
while (myInt << myIstream) {…} //Will fail when I am at the end
but the same check would fail for a number of different conditions (say I have something which is not an int on some line) and being able to differentiate between the two reading errors (unexpected thing, nothing left) would help me to write more robust code, as I could write:
while (something_left(myIstream)) {
myInt << myIstream;
if (myStream.fail()) {…} //Horrible things happened
}
Thank you!
There is a function called ws which eats whitespace. Perhaps you could call that after each read. If that hits eof, then you know you've got a normal termination. If it doesn't and the next read doesn't produce a valid int, then you know you've got garbage in your file. Maybe something like:
#include <fstream>
#include <iostream>
int main()
{
std::ifstream infile("test.dat");
while (infile)
{
int i;
infile >> i;
if (!infile.fail())
std::cout << i << '\n';
else
std::cout << "garbage\n";
ws(infile);
}
}
this is what I did to skip whitespace/detect EOF before the actual input:
char c;
if (!(cin >> c)) //skip whitespace
return false; // EOF or other error
cin.unget();
This is independent of what data you are going to read.
This code relies on the skipws manipulator being set by default for standard streams, but it can be set manually cin >> skipw >> c;
And simple
for(;;){
if(!(myIstream >> myInt)){
if(myIstream.eof()) {
//end of file
}else{
//not an integer
}
}
// Do something with myInt
}
does not work? Why you need to know if there are numbers left?
Edit Changed to Ben's proposition.
The usual way to handle this situation is not to avoid reading from the stream, but to put back characters, which have been read, if needed:
int get_int(std::istream& in)
{
int n = 0;
while(true) {
if (in >> n)
return n;
clean_input(in);
}
}
void clean_input(std::istream& in)
{
if (in.fail()) {
in.clear();
// throw away (skip) pending characters in input
// which are non-digits
char ch;
while (in >> ch) {
if (isdigit(ch)) {
// stuff digit back into the stream
in.unget();
return;
}
}
}
error("No input"); // eof or bad
}