Reading from CSV and storing in a Vector - c++

Consider I have the following csv file:
10.0.0.26
10.0.0.30
10.0.0.34
10.0.0.38
...
...
Consider I have a vector:
std::vector<L3Address> destAddresses;
I want a piece of code the will read the above csv file till the very last address and store each of that address in the above vector.
std::ifstream data("data.csv");
while(//till the end of file){
//read from csv
//write to vector
}
I have tried the following:
std::ifstream data("data.csv");
while(std::getline(data,std::string value){
destAddresses.push_back(value);
}
But this isn't working somehow.

Let's go look at the documentation of L3Address (note 1). Here we can see a function bool L3Address::tryParse(const char * str), which will try to interpret a C-string as an address, and tell you if it succeded.
std::ifstream data("data.csv");
std::string line;
while (std::getline(data, line) {
L3Address addr;
if (addr.tryParse(line.c_str())) {
destAddresses.push_back(addr);
}
else
{
// TODO: handle malformed address
}
}
Note 1: The tooling that generated this documentation is formatting it very badly, so it is excusable that you couldn't get here yourself.

Your example doesn't seem to compile. Besides the missing parenthesis the getline function you are using requires a variable reference as the second argument. Hence, you should fix your code by defining the value variable before use.
Additionally to construct the L3Address you can benefit from the constructor accepting const char*.
std::ifstream data("data.csv");
std::string value;
while(std::getline(data,value))
{
destAddresses.emplace_back(value.c_str());
}

Related

ifstream as class member [duplicate]

I have the following parser class that works in Visual C++
class Parser
{
private:
const char* filename;
std::ifstream filestream;
std::vector<std::string> tokens;
unsigned int linect;
public:
Parser(const char* filename);
bool readline();
std::string getstrtoken(unsigned int i) const { return tokens[i]; }
int getinttoken(unsigned int i) const { return atoi(tokens[i].c_str()); }
};
Parser::Parser(const char* filename) :
filename(filename),
linect(0)
{
filestream = ifstream(filename); // OK in VC++, not with GCC?
}
bool Parser::readline()
{
std::string line;
getline(filestream, line);
std::stringstream ss(line);
std::string token;
tokens.clear();
while(getline(ss, token, ' ')){ if(token != "") tokens.push_back(token); }
linect++;
return (filestream != NULL);
}
But when I try to compile it with GCC 4.8.2, I get errors saying that I cannot assign to filestream. From what I read elsewhere on this site, you can do
std::ifstream filestream(filename);
but you cannot do
std::ifstream filestream;
filestream = ifstream(filename);
which is essentially what I need to do if I want to declare filestream as a member of the Parser class and initialize it in the constructor.
I would like to have the file stream kept within the Parser class so that those who use the parser don't need to declare and keep track of it. It seems to me that this should be self-contained in the Parser class since its internal methods (e.g. readline()) are the only ones that use it.
Is there a way to achieve this that works with both platforms?
Thanks.
edit: My fix was to explicitly call the open() method of ifstream. My parser class constructor now looks like:
Parser::Parser(const char* filename) :
filename(filename),
linect(0)
{
filestream.open(filename);
// Do some checking to make sure the file exists, etc.
}
You can't, since std::ifstream has deleted copy constructor and copy assignment. You may get around by doing
filestream.swap(ifstream(filename)).
The fact that it compiles on visual studio is mostly because it gets inlined into either move assignment or move constructor(I'm not so good to tell you which exactly). If you try
std::ifstream myF;
filestream = myF;
it won't compile.
However you may try to do the move I wrote, or you can just call .open(http://en.cppreference.com/w/cpp/io/basic_ifstream/open)
I think a better solution would be for you to:
Construct a ifstream first.
Construct a Parser using the ifstream object.
Change Parser to store a reference to an istream object. This allows you the flexibility of being able parse the contents of a file, stdin, and a string.
class Parser
{
private:
std::istream& str;
std::vector<std::string> tokens;
unsigned int linect;
public:
Parser(std::istream& s) : str(s) ... {}
...
};
std::ifstream don't have a copy constructor, probably one of the many extensions of VC++. Correct code is:
Parser::Parser(const char* filename) :
filename(filename),
linect(0),
filestream(filename)
{
}
Please take note of member variable and parameter filename. Use this-> or change name (recommended, normally prefix is used for member variables _ or m_)

no instance of overloaded function

trying to do a project for class, but keep getting the error: no instance of overloaded function matches argument list relating to the implementation of the rows vector. the area that is specifically highlighted is the . operator before push_back and insert.
void holdLines(ifstream in, vector<string> rows) {
string line;
string prevLine;
vector<string> rows;
int lineNumber = 0;
int vectorNumber = 0;
while(true) {
getline(in, line);
if(in.fail()) {
break;
}
lineNumber++;
vectorNumber = lineNumber - 1;
rows.push_back(lineNumber);
rows.insert(prevLine, line);
}
}
You are trying to pass an integer to push_back when a string is required.
It also looks like your local variable "rows" is named the same as your parameter "rows".
http://www.cplusplus.com/reference/vector/vector/push_back/
Your compiler is correct: there is no overload of std::vector<std::string>::push_back that accepts an int, because a std::vector<std::string> stores std::strings, not ints.
It's quite unclear from code alone what you are trying to do, due to the myriad mistakes, but start by replacing your push_back call with something sensible.
There is no method insert with two parameters of type std::string as you are trying to call
rows.insert(prevLine, line);
Also it is not clear what you are trying to do in this statement.
Edit: After you updated yor code nevertheless this statemenet
rows.push_back(lineNumber);
also is wrong because the rows is declared as a vecto of strings. It is not a vector of int and moreover class std::string does not have an appropriate constructor.
But in any case the function does not make sense because you declared a local variable with the same name as the second parameter and tried to fill this local vector that will be deleted after exiting the function
void holdLines(ifstream in, vector<string> rows) {
^^^^^^^^^^^^^^^^^^
string line;
string prevLine;
vector<string> rows;
^^^^^^^^^^^^^^^^^^^^
//..
I think the function should be declared either like
void holdLines(ifstream in, vector<string> &rows);
^^^
or like
vector<string> holdLines(ifstream in);
Take into account that instead of this statements
while(true) {
getline(in, line);
if(in.fail()) {
break;
}
//...
you could write
while ( getline( in, line ) )
{
//...
If you need simply to fill the vector that is passed as the argument then the function can look the following way
void holdLines( std::ifstream &in, std::vector<std::string> &rows )
{
std::string line;
while ( std::getline( in, line ) ) rows.push_back( line );
}

Initializing "const std::string" from "std::istringstream"

I'm trying to parse a file which is in Key<whitespace>Value format. I'm reading the file lines in an std::istringstream object, and I'm extracting a Key string from it. I want to avoid accidentally changing the value of this Key string by making it const.
My best attempt was initializing a temporary VariableKey object, and then making a constant one out of it.
std::ifstream FileStream(FileLocation);
std::string FileLine;
while (std::getline(FileStream, FileLine))
{
std::istringstream iss(FileLine);
std::string VariableKey;
iss >> VariableKey;
const std::string Key(std::move(VariableKey));
// ...
// A very long and complex parsing algorithm
// which uses `Key` in a lot of places.
// ...
}
How do I directly initialize a constant Key string object?
It's arguably better to separate file I/O from processing, and instead of creating a const Key inside the same function - call a line-processing function that takes a const std::string& key parameter.
That said, if you want to continue with your current model, you can simply use:
const std::string& Key = VariableKey;
There's no need to copy or move anything anywhere. Only const std::string members functions will be accessible via Key.
You can avoid the "scratch" variable by extracting the input into a function:
std::string get_string(std::istream& is)
{
std::string s;
is >> s;
return s;
}
// ...
while (std::getline(FileStream, FileLine))
{
std::istringstream iss(FileLine);
const std::string& Key = get_string(iss);
// ...
(Binding the function's result to a const reference extends its lifetime.)

How to have a file stream as a class member

I have the following parser class that works in Visual C++
class Parser
{
private:
const char* filename;
std::ifstream filestream;
std::vector<std::string> tokens;
unsigned int linect;
public:
Parser(const char* filename);
bool readline();
std::string getstrtoken(unsigned int i) const { return tokens[i]; }
int getinttoken(unsigned int i) const { return atoi(tokens[i].c_str()); }
};
Parser::Parser(const char* filename) :
filename(filename),
linect(0)
{
filestream = ifstream(filename); // OK in VC++, not with GCC?
}
bool Parser::readline()
{
std::string line;
getline(filestream, line);
std::stringstream ss(line);
std::string token;
tokens.clear();
while(getline(ss, token, ' ')){ if(token != "") tokens.push_back(token); }
linect++;
return (filestream != NULL);
}
But when I try to compile it with GCC 4.8.2, I get errors saying that I cannot assign to filestream. From what I read elsewhere on this site, you can do
std::ifstream filestream(filename);
but you cannot do
std::ifstream filestream;
filestream = ifstream(filename);
which is essentially what I need to do if I want to declare filestream as a member of the Parser class and initialize it in the constructor.
I would like to have the file stream kept within the Parser class so that those who use the parser don't need to declare and keep track of it. It seems to me that this should be self-contained in the Parser class since its internal methods (e.g. readline()) are the only ones that use it.
Is there a way to achieve this that works with both platforms?
Thanks.
edit: My fix was to explicitly call the open() method of ifstream. My parser class constructor now looks like:
Parser::Parser(const char* filename) :
filename(filename),
linect(0)
{
filestream.open(filename);
// Do some checking to make sure the file exists, etc.
}
You can't, since std::ifstream has deleted copy constructor and copy assignment. You may get around by doing
filestream.swap(ifstream(filename)).
The fact that it compiles on visual studio is mostly because it gets inlined into either move assignment or move constructor(I'm not so good to tell you which exactly). If you try
std::ifstream myF;
filestream = myF;
it won't compile.
However you may try to do the move I wrote, or you can just call .open(http://en.cppreference.com/w/cpp/io/basic_ifstream/open)
I think a better solution would be for you to:
Construct a ifstream first.
Construct a Parser using the ifstream object.
Change Parser to store a reference to an istream object. This allows you the flexibility of being able parse the contents of a file, stdin, and a string.
class Parser
{
private:
std::istream& str;
std::vector<std::string> tokens;
unsigned int linect;
public:
Parser(std::istream& s) : str(s) ... {}
...
};
std::ifstream don't have a copy constructor, probably one of the many extensions of VC++. Correct code is:
Parser::Parser(const char* filename) :
filename(filename),
linect(0),
filestream(filename)
{
}
Please take note of member variable and parameter filename. Use this-> or change name (recommended, normally prefix is used for member variables _ or m_)

Error Using std::vector<std::string> myString

Hi it's a little bit hard for me to understand what the compiler is saying:
[BCC32 Error] frmNew.cpp(333): E2285 Could not find a match for 'std::getline<_Elem,_Traits,_Alloc>(ifstream,std::vectorstd::string,std::allocator<std::string >)'
Full parser context
frmNew.cpp(303): parsing: void _fastcall TFrmNewPeta::showDefaultRute()
I'm using std::vector<std::string>mystring to store my strings file, but
while (std::getline(ifs_Awal, mystring)) throws the error.
This is my complete code:
void __fastcall TFrmNewPeta::showDefaultRute()
{
std::string mystring;
std::ifstream ifs_Awal;
int tempIndexAwal = 0;
ifs_Awal.open("DefaultDataAwal");
while (std::getline(ifs_Awal, mystring)) {++tempIndexAwal;}
std::vector<std::string> mystring(tempIndexAwal);
while (std::getline(ifs_Awal, mystring)) // error
{
mystring.push_back(mystring); // error
}
ifs_Awal.close();
}
I'm using C++ Builder 2010.
In many tutorials they prefer to using std::vector to store a string to a dynamic array. So I did the same thing, but the error occurred when I tried using std::vector<>.
second parameter of std::getline could be std::string but not std::vector<std::string>. It's quite clear as error message shows.
update
std::vector<std::string> mystring(tempIndexAwal);
to:
std::string mystring;
You do not post how you declare myline, I suppose it's std::vector<std::string>.
billz and tomi rights your passing wrong argument so I change your code. should be
void __fastcall TFrmNewPeta::showDefaultRute() {
std::string lines;
std::ifstream ifs_Awal;
int tempIndexAwal = 0;
ifs_Awal.open("DefaultDataAwal");
/*get the strings and counting the lines*/
while(std::getline(ifs_Awal,lines)){++tempIndexAwal;}
std::vector<std::string> mystring(tempIndexAwal);
while(std::getline(ifs_Awal,lines)) //put your 'lines' here
{
mystring.push_back(lines); // theres no error again :)
}
ifs_Awal.close();
}
Your passing wrong argument to getline.
mystring is not a std::string as it should be, but a std::vector. Thus line
std::getline(ifs_Awal,mystring) causes an error since the second argument is not std::string.
Also, line
myline.push_back(mystring)
does not work because myline is probably a vector of string, and you try to push an element of vector<string> to it.
So, as suggested already, changing myline to std::string is the answer.