Reading a csv line. Problem with the last element - c++

I have the following function
void get_inspva(const std::string line){
std::cout<<") "<<line<<std::endl;
std::istringstream iss(line);
std::string lineStream;
while (getline(iss,lineStream,',')){
std::cout<<"["<<lineStream<<"]"<<std::endl;
}
}
When I have a line like this:
a_line="1618378741,521574939,1618378741.55,36.10726662693096,139.97386621160913,57.3723646402359,-1.9803314791186484,-0.5150965223798682,0.021916236872909,-0.02259244492482216,0.09830296322174402,3.404935980746039,GOOD";
and I call get_inspva(a_line) I get
[1618378741]
[521574939]
[1618378741.55]
[36.10726662693096]
[139.97386621160913]
[57.3723646402359]
[-1.9803314791186484]
[-0.5150965223798682]
[0.021916236872909]
[-0.02259244492482216]
[0.09830296322174402]
[3.404935980746039]
]GOOD
Why is the last cout not working as it should?
EDIT:
The lines I am getting them from a csv file like
std::ifstream file(input_file);
std::string input_line;
int i=0;
while(getline(file,input_line)){
// std::cout<<i<<") "<<input_line<<std::endl;
// Here we process the input_line
get_inspva(input_line);
}
file.close();

Related

How to split the elements of a text file in C++

i have a text file called builders.txt that contains some data
Reliable Rover:70:1.
Sloppy Simon:20:4.
Technical Tom:90:3.
Within my main file i have a function declaration related to this specific text file
void Builder() {
std:string name;
int ability;
int variability;
}
this is my read file function
std::vector<std::string> lines;
std::string inputFile1 = "Builders.txt";
std::string inputFile2 = "Parts.txt";
std::string inputFile3 = "Customers.txt";
std::string outputFile = "output.txt";
std::string input;
void readFile(std::string const& inputFile1, std::string const& inputFile2, std::string const& inputFile3,
std::vector<std::string>& lines) //function to read Builders, Customers and Parts text file
{
std::ifstream file1(inputFile1);
std::ifstream file2(inputFile2);
std::ifstream file3(inputFile3);
std::string line;
while(std::getline(file1, line))
{
lines.push_back(line);
}
while(std::getline(file2, line))
{
lines.push_back(line);
}
while(std::getline(file3, line))
{
lines.push_back(line);
}
}
This is my attempt
std::vector<std::string> lines;
std::string inputFile1 = "Builders.txt";
std::istringstream newStream(inputFile1);
std::string input;
void readFile(std::string const& newStream,std::vector<std::string>& lines)
{
std::ifstream file1(newStream);
std::string line;
while(std::getline(file1, line,":"))
{
lines.push_back(line);
}
When i run this code i recieve the error "no instance of overload function getline"
My question is given the text file how can i split the text file so that, for example, Reliable Rover is the name, 70 is the ability and 1 is the variability for the 1st record. Another example would be Sloppy Simon being the name, 20 being the ability and 4 being variaiblity. If the question is to vague or requires futher details please let me know
Thankyou
As #thomas-sablik mentioned, a simple solution is to read the file line by line and read each element from the line:
std::ifstream f("builder.txt");
std::string line;
// read each line
while (std::getline(f, line)) {
std::string token;
std::istringstream ss(line);
// then read each element by delimiter
while (std::getline(ss, token, ':'))
std::cout << token << std::endl;
}
don't forget to include sstream for using stringstreams.
Note: refer to cppreference, third parameter of std::getline is delim and is a character but you pass it as a string. So change:
while(std::getline(file1, line,":"))
to:
while(std::getline(file1, line,':'))
Here is a naive approach I came up with:
std::string name;
int ability;
int variability;
char read;
while (ifs >> read) { // read until the end of the file
// adding read into name
while (read != ':') {
name += read;
ifs >> read;
}
ifs >> ability;
ifs >> read; // Remove ':'
ifs >> variability;
ifs >> read; // Remove '.'
// Code to deal with the three variables
name = "";
}
Hope it helps.

fstream reading error (only reading first line)

I want to read a file with std::getline. but reads first line only
string FileReader::readLine() {
string line;
string read;
ifstream ReadFile;
ReadFile.open("input.txt");
if (ReadFile.is_open()) {
getline(ReadFile, line);
//ReadFile.close();
}
return line;
}
this is my method. I call this method several time but always reads first line how can i do to read next lines?
You need to change your program flow.
Don't return a string. Use the line within the loop to do whatever it is you want. Ensuring that you either don't leave the method or return to it.
You can't keep coming back to a function like this, as it will keep reading from the beginning.
void FileReader::readLine() {
string line;
string read;
ifstream ReadFile;
ReadFile.open("input.txt");
if (ReadFile.is_open()) {
while(getline(ReadFile, line))
{
//do what you want with that line, but return program flow here.
}
ReadFile.close();
}
}

Reading a file into memory C++: Is there a getline() for std::strings

I was asked to update my code that reads in a text file and parses it for specific strings.
Basically instead of opening the text file every time, I want to read the text file into memory and have it for the duration of the object.
I was wondering if there was a similar function to getline() I could use for a std::string like i can for a std::ifstream.
I realize I could just use a while/for loop but I am curious if there is some other way. Here is what I am currently doing:
file.txt: (\n represents a newline )
file.txt
My Code:
ifstream file("/tmp/file.txt");
int argIndex = 0;
std::string arg,line,substring,whatIneed1,whatIneed2;
if(file)
{
while(std::getline(file,line))
{
if(line.find("3421",0) != string::npos)
{
std::getline(file,line);
std::getline(file,line);
std::stringstream ss1(line);
std::getline(file,line);
std::stringstream ss2(line);
while( ss1 >> arg)
{
if( argIndex==0)
{
whatIneed1 = arg;
}
argIndex++;
}
argIndex=0;
while( ss2 >> arg)
{
if( argIndex==0)
{
whatIneed2 = arg;
}
argIndex++;
}
argIndex=0;
}
}
}
Where at the end whatIneed1=="whatIneed1" and whatIneed2=="whatIneed2".
Is there a way to do this with storing file.txt in a std::string instead of a std::ifstream asnd using a function like getline()? I like getline() because it makes getting the next line of the file that much easier.
If you've already read the data into a string, you can use std::stringstream to turn it into a file-like object compatible with getline.
std::stringstream ss;
ss.str(file_contents_str);
std::string line;
while (std::getline(ss, line))
// ...
Rather than grab a line then try to extract one thing from it, why not extract the one thing, then discard the line?
std::string whatIneed1, whatIneed2, ignored;
if(ifstream file("/tmp/file.txt"))
{
for(std::string line; std::getline(file,line);)
{
if(line.find("3421",0) != string::npos)
{
std::getline(file, ignored);
file >> whatIneed1;
std::getline(file, ignored);
file >> whatIneed2;
std::getline(file, ignored);
}
}
}

Stream object to represent file input and then standard input?

As a noob C++ project, I am building a CLI game with a game loop that relies upon user input. For the purpose of testing, I would like to be able to pass a file name as a command line argument to the program, which will be treated "like standard input" until it is read through.
Consequently, I need a way to encapsulate an object that represents a file's contents and then std::cin once the file has been read through - basically prepending a file's contents to standard input. At least, this seems like it would be very nice, so that I can avoid having something like
std::istringstream retrieve_input(std::ifstream &file) {
std::string line;
if (std::getline(file, line))
return std::istringstream{line};
std::getline(std::cin, line);
return std::istringstream{line};
}
Is replacing this with some kind of custom class a good approach? Or can I mess with std::cin somehow to prepend my file contents to it?
To clarify : My game loop might have say, 20 iterations. If I pass a file with five lines, I want to use those five lines for the first five iterations of my game loop, and then drop back to standard input for the remaining fifteen. I understand how to do this with a bunch of conditions, but I think there must be a way to nicely have this sort of behavior in a class. My problem is - what should it inherit from? std::streambuf? Is this a good idea in principle?
My (probably bad attempt)
class InputGrabber {
public:
virtual std::istringstream retrieve_line() = 0;
virtual ~InputGrabber() {}
};
class BaseInputGrabber : public InputGrabber {
public:
BaseInputGrabber(std::istream &_in): in{_in} {}
std::istringstream retrieve_line() override {
std::string line;
std::getline(in, line);
return std::istringstream{line};
}
private:
std::istream &in;
};
class VarInputGrabber : public InputGrabber {
public:
VarInputGrabber(std::istream &_in, const std::string &f_name) :
in{_in}, init{std::ifstream(f_name)} {}
std::istringstream retrieve_line() override {
std::string line;
if (std::getline(init, line)) {
return std::istringstream{line};
}
std::getline(in, line);
return std::istringstream{line};
}
private:
std::istream &in;
std::ifstream init;
};
Would the below work? You open the file, redirect std::cin to read from the file. Use std::getline on std::cin so that it reads from the file stream. Some time before the program ends or if the file is finished being read, restore std::cin back to its original state.
#include <iostream>
#include <fstream>
int main(int argc, const char * argv[]) {
std::fstream file("/users/Brandon/Desktop/testingInput.txt", std::ios::in);
//Redirect cin to a file.
std::streambuf* cinBuffer = std::cin.rdbuf();
std::cin.rdbuf(file.rdbuf());
//Read line from std::cin (which points to the file) with std::getline.
std::string line;
std::getline(std::cin, line);
std::cout<<"INPUT LINE: "<<line<<std::endl;
//Redirect cin to standard input.
std::cin.rdbuf(cinBuffer);
//Read some line from the user's input..
std::getline(std::cin, line);
std::cout<<"USER INPUT LINE: "<<line<<std::endl;
std::cin.get();
return 0;
}
You could always redirect from file via argv. Treat the whole thing as std::cin from the beginning.
Is the following example that what you are looking for?
std::string readNextLine(std::istream& is)
{
std::string line;
if(!std::getline(is, line))
std::getline(std::cin, line);
return line;
}
int main()
{
std::stringstream ss ("a\nb\nc\n");
for(int i = 0; i < 5; ++i)
{
auto line = readNextLine(ss);
std::cout << "got: " << line << std::endl;
}
return 0;
}
The stringstream can be replaced with fstream or any other type that implements std::istream.
You can test it here http://cpp.sh/5iv65

Creating String Array from CSV

I have a csv file of atomic elements with atomic number, symbol, and name. The file is formatted as:
1,H,Hydrogen
2,He,Helium
3,Li,Lithium
...
I'd like to create an array of the symbols referenced by the atomic number. ie. ArrayName[32]="Ge";
I've been trying to use sscanf but it hasn't been working. rough code below:
char temp[200];
float temp_z;
std::string temp_ele;
std::string temp_name;
while(!fin.eof())
{
fin.getline(temp,200);
sscanf(temp, "\"%f\",\"%s\", \"%s\"",&temp_z, &temp_ele, &temp_name);
cout<<temp_z<<endl;
cout<<temp_ele<<endl;
cout<<temp_name<<endl;
}
Read every line of your file with this loop :
string line;
ifstream myfile;
myfile.open("myfile.txt");
if(!myfile.is_open()) {
perror("Error open");
exit(EXIT_FAILURE);
}
while(getline(myfile, line)) {
// Split line by comma to get what's your want
}
Then split every line by comma to get every element of the line.
You can read each element like so:
string theStrings[200]; //initialize to correct size
int i = 0;
string name;
while(!fin.eof())
{
getline(thefilestream, name, ',' );
theStrings[i++] = name;
cout<<name<<endl;
}