Fill vector of string vectors from input file - c++

I would really appreciate the help here. I need to fill a vector of string vectors using text from an input file. I really have no idea how to start off.
I have something like this in a function to read in the words, but I keep getting a compiler error saying I can't push back a string, so I know I'm on the wrong track. Any help would be very much appreciated.
ifstream input(filename);
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
string line;
getline(input, line);
stringstream temp(line);
string tempWord;
temp >> tempWord;
words[i][j].push_back(tempWord);
}

If words is a vector<vector<string>> then words[i][j] is accessing a string. What you might looking to do is is words[i][j] = tempWord;. string also has a function .push_back() but takes a char which is why the error you are getting is that you can't push_back a string, the push_back() for strings is for appending characters to the string. Also depending on how you declared words, if you didn't give sizes, words[i][j] might be accessing out of range and a better approach would be to do words[i].push_back(tempWord). Also looking at your for loops I'm not sure of your intent for which words from the file you want but currently as your code is, it will read in the first 16 lines of the file and place the first "word" from each into your words object. If your intent is instead to have a vector of vectors of string where each subvector is the words in a line then something like below might be better.
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
int main(int argc, char* argv[])
{
std::string filename = "testfile.txt";
std::ifstream input(filename.c_str());
if(!input){
std::cerr << "Error in opening file: " << filename << "\n";
return 1;
}
std::vector<std::vector<std::string> > words;
std::string line;
while(std::getline(input, line)){
std::stringstream ss;
ss << line;
std::vector<std::string> row;
while (!ss.eof()) {
std::string tempStr;
ss >> tempStr;
row.push_back(tempStr);
}
words.push_back(row);
}
//... then do something with words here
return 0;
}

Related

Passing a file via command arguement into an array

So I'm trying to pass and command line argument into an array in my int main
like this $< .\program nums.txt 8 but I'm getting errors and hit a dead-end with my knowledge on C++ code. (I'm relatively a new coder). Any help is greatly appreciated.
int main(int argc,char *argv[])
{
string arg2=" ";
arg2 = argv[2];
int size;
size=stod(arg2);
string arr[size];
string file = argv[1];
ifstream infile;
if (getline infile.open(file))
{
int arr[size],val;
for(int i=0;i<size;i++)
{
getline(file, arr[i]);
}
}
int choice = 5,value,position,target ;
Her is a list of the errors you have (excluding a missing curly brace at the end, missing includes [you probably just didn't post them?] and missing std:: [the use of using namespace std; is considered bad practice ]) and mostly how to fix them:
std::stod parses and returns a dobule, but you assign the result to an int.
size = std::stod(arg2);
you probably meant to use stoi:
size = std::stoi(arg2);
VLAs (Variable length arrays) like
std::string arr[size];
are not part of the C++ standard. Instead use
std::vector<std::string> arr(size);
When opening the file stream, your inention is right, but the syntax is wrong
std::ifstream infile;
if (std::getline infile.open(file))
should be
std::ifstream infile(file);
if (infile)
Inside the if you have
int arr[size],val;
two unused variables, another VLA and most importantly int arr[size] will shadow string arr[size].
That's the reason for the next errors:
std::getline(file, arr[i]);
The first parameter file is a std::string, this should obviosly be infile. Because of the variable shadowing the second parameter arr[i] will refer to int arr[i]. Rename one of them or just remove the two unused variables (see last point).
Always check if reading was successfull. If you want to read a maximum of size lines use
for(int i = 0; i < size && std::getline(infile, arr[i]); i++);
It will terminate the loop, if getline fails for some reason, for example, when the file has less than size lines.
Lastly, you can think about some validation. For example check if there actually are two command line parameters given and add a try-catch-block around the stoi.
And just to mention it: Learning C++ by guessing is no fun. On https://en.cppreference.com/w/ you can find extensive information and many examples for the functions and classes you want to use.
There are lot of typos in your question. Still I think this code may help you:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
int main(int argc, char *argv[]) {
int size = atoi(argv[2]);
std::vector<std::string> arr(size);
std::ifstream infile(argv[1]);
if (not infile) {
std::cerr << "File not found!" << std::endl;
return -1;
}
for (int i = 0; i < size; i++)
if (infile)
std::getline(infile, arr[i]);
else {
std::cerr << "Not enough lines in the file!" << std::endl;
return -2;
}
// do rest of your things here ...
return 0;
}

C++ Read in a file like a grid

I'm coding in C++ and I'm trying to read in a file that I'd like to access certain chars at later. As in, what is the char at (line x, char y), at any given point in the file.
My only thought right now is to look for a newline character, and somehow index them so that I can refer back to newline x, check the length of a line, and pull a char at whatever position given the line length.
I'm not sure if that is a good approach or not.
Try this (for character in line "lineNum" and column "columnNum"):
ifstream inf;
inf.open(filename); //filename being c-string
string str;
for (int i = 0; i < lineNum; i++)
{
std::getline(inf, str);
}
This way "str" stores the line you are interested in (automatically checks for newline character and stops).
Then you can use:
char chr = str[columnNum];
to store the character you want in "chr" variable. And don't forget:
inf.close();
Unfortunately, to my knowledge you need to repeat this process every time you want to access a character.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#define FILENAME "File.txt"
class FileGrid {
public:
typedef std::vector<std::string> Line;
typedef std::vector<std::string>::const_iterator LineIter;
typedef std::vector<std::vector<std::string>> StringMap;
typedef std::vector<std::vector<std::string>>::const_iterator StringMapIter;
void FillGrid(char* fileName) {
grid.clear();
std::ifstream in(FILENAME, std::ifstream::in);
if (!in.is_open()) {
std::cout << "problem reading " << FILENAME << std::endl;
return;
}
std::string words;
std::string word;
std::stringbuf buffer;
while (in.is_open() && std::getline(in, words)) {
std::stringstream ss(words);
Line line;
while (ss >> word) {
line.push_back(word);
}
grid.push_back(line);
}
}
void PrintGrid() {
StringMapIter b = grid.begin();
StringMapIter e = grid.end();
std::cout << "\t\tFile Content:" << std::endl;
while(b != e) {
for (unsigned int i = 0; i < b->size(); ++i) {
std::cout << b->operator[](i) << " ";
}
std::cout << std::endl;
++b;
}
}
char const & GetChar(int lineNo, int charNo) {
// LineNo checks etc
Line const & line = grid[lineNo];
for(std::string const & word : line ) {
if(charNo > word.size() + 1) {
charNo -= word.size() + 1;
}
else {
return word[charNo];
}
}
throw std::exception("charNo higher");
}
private:
StringMap grid;
};
void main() {
FileGrid grid;
grid.FillGrid(FILENAME);
grid.PrintGrid();
std::cout << grid.GetChar(0, 3); // should return first line, 4th character
}
Not the best code I've ever written but pretty much what I could do in a short time.
FileGrid handles reading and accessing the data. It reads the file line by line and stores it in a std::vector. When it finishes reading a line, it pushes that into another std::vector. In the end, we have a (sort of) 2D array of strings.
Again, not the best code and definitely not the most optimized code but the idea is still the same: read from the file line by line, separate each word and put them into an array of strings. If you can't use STL, you can dynamically create a 2D array for each line but since I don't know the specific requirements of your question, I just wrote something simple and bruteforce to show you the main way of storing grid of strings into the memory.
As long as it works. But reading the entire file into memory, if that's an option, would be simpler.

Reading data in from a .csv into usable format using C++

I would like to be able to read the data that I have into C++ and then start to do things to manipulate it. I am quite new but have a tiny bit of basic knowledge. The most obvious way of doing this that strikes me (and maybe this comes from using excel previously) would be to read the data into a 2d array. This is the code that I have so far.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>
#include <sstream>
using namespace std;
string C_J;
int main()
{
float data[1000000][10];
ifstream C_J_input;
C_J_input.open("/Users/RT/B/CJ.csv");
if (!C_J_input) return -1;
for(int row = 0; row <1000000; row++)
{
string line;
getline(C_J_input, C_J, '?');
if ( !C_J_input.good() )
break;
stringstream iss(line);
for(int col = 0; col < 10; col++)
{
string val;
getline(iss, val, ',');
if (!iss.good() )
break;
stringstream converter(val);
converter >> data[row][col];
}
}
cout << data;
return 0;
}
Once I have the data read in I would like to be able to read through it line by line and then pull analyse it, looking for certain things however I think that could probably be the topic of another thread, once I have the data read in.
Just let me know if this is a bad question in any way and I will try to add anything more that might make it better.
Thanks!
as request of the asker, this is how you would load it into a string, then split into lines, and then further split into elements:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream>
//This takes a string and splits it with a delimiter and returns a vector of strings
std::vector<std::string> &SplitString(const std::string &s, char delim, std::vector<std::string> &elems)
{
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim))
{
elems.push_back(item);
}
return elems;
}
int main(int argc, char* argv[])
{
//load the file with ifstream
std::ifstream t("test.csv");
if (!t)
{
std::cout << "Unknown File" << std::endl;
return 1;
}
//this is just a block of code designed to load the whole file into one string
std::string str;
//this sets the read position to the end
t.seekg(0, std::ios::end);
str.reserve(t.tellg());//this gives the string enough memory to allocate up the the read position of the file (which is the end)
t.seekg(0, std::ios::beg);//this sets the read position back to the beginning to start reading it
//this takes the everything in the stream (the file data) and loads it into the string.
//istreambuf_iterator is used to loop through the contents of the stream (t), and in this case go up to the end.
str.assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
//if (sizeof(rawData) != *rawSize)
// return false;
//if the file has size (is not empty) then analyze
if (str.length() > 0)
{
//the file is loaded
//split by delimeter(which is the newline character)
std::vector<std::string> lines;//this holds a string for each line in the file
SplitString(str, '\n', lines);
//each element in the vector holds a vector of of elements(strings between commas)
std::vector<std::vector<std::string> > LineElements;
//for each line
for (auto it : lines)
{
//this is a vector of elements in this line
std::vector<std::string> elementsInLine;
//split with the comma, this would seperate "one,two,three" into {"one","two","three"}
SplitString(it, ',', elementsInLine);
//take the elements in this line, and add it to the line-element vector
LineElements.push_back(elementsInLine);
}
//this displays each element in an organized fashion
//for each line
for (auto it : LineElements)
{
//for each element IN that line
for (auto i : it)
{
//if it is not the last element in the line, then insert comma
if (i != it.back())
std::cout << i << ',';
else
std::cout << i;//last element does not get a trailing comma
}
//the end of the line
std::cout << '\n';
}
}
else
{
std::cout << "File Is empty" << std::endl;
return 1;
}
system("PAUSE");
return 0;
}
On second glance, I've noticed few obvious issues which will slow your progress greatly, so I'll drop them here:
1) you are using two disconnected variables for reading the lines:
C_J - which receives data from getline function
line - which is used as the source of stringstream
I'm pretty sure that the C_J is completely unnecessary. I think you wanted to simply do
getline(C_J_input, line, ...) // so that the textline read will fly to the LINE var
// ...and later
stringstream iss(line); // no change
or, alternatively:
getline(C_J_input, C_J, ...) // no change
// ...and later
stringstream iss(C_J); // so that ISS will read the textline we've just read
elsewise, the stringstream will never see what getline has read form the file - getline writes the data to different place (C_J) than the stringstream looks at (line).
2) another tiny bit is that you are feeding a '?' into getline() as the line separator. CSVs usually use a 'newline' character to separate the data lines. Of course, your input file may use '?' - I dont know. But if you wanted to use a newline instead then omit the parameter at all, getline will use default newline character matching your OS, and this will probably be just OK.
3) your array of float is, um huge. Consider using list instead. It will nicely grow as you read rows. You can even nest them, so list<list<float>> is also very usable. I'd actually probably use list<vector<float>> as the number of columns is constant though. Using a preallocated huge array is not a good idea, as there always be a file with one-line-too-much you know and ka-boom.
4) your code contains a just-as-huge loop that iterates a constant number of times. A loop itself is ok, but the linecount will vary. You actually don't need to count the lines. Especially if you use list<> to store the values. Just like you;ve checked if the file is properly open if(!C_J_input), you may also check if you have reached End-Of-File:
if(C_J_input.eof())
; // will fire ONLY if you are at the end of the file.
see here for an example
uh.. well, that's for start. Goodluck!

To store tokens into an array

A novice at C++, i am trying to create a stats program to practice coding. i am hoping to get a text file, read it and store values into arrays on which i can perform mathematical operations. i am stuck here
main ()
{
char output[100];
char *charptr;
int age[100];
ifstream inFile;
inFile.open("data.txt");
if(!inFile)
{
cout<<"didn't work";
cin.get();
exit (1);
}
inFile.getline(output,100);
charptr = strtok(output," ");
for (int x=0;x<105;x++)
{
age[x] = atoi(charptr);
cout<<*age<<endl;
}
cin.get();
}
in the code above, I am trying to store subject ages into the int array 'age', keeping ages in the first line of the file. I intend to use strtok as mentioned, but i am unable to convert the tokens into the array.
As you can obviously see, I am a complete noob please bear with me as I am learning this on my own. :)
Thanks
P.S: I have read similar threads but am unable to follow the detailed code given there.
There are a few issues with the for loop:
Possibility of going out-of-bounds due to age having 100 elements, but terminating condition in for loop is x < 105
No check on charptr being NULL prior to use
No subsequent call to strtok() inside for loop
Printing of age elements is incorrect
The following would be example fix of the for loop:
charptr = strtok(output, " ");
int x = 0;
while (charptr && x < sizeof(age)/sizeof(age[0]))
{
age[x] = atoi(charptr);
cout << age[x] << endl;
charptr = strtok(NULL, " ");
x++;
}
As this is C++, suggest:
using std::vector<int> instead of a fixed size array
use the std::getline() to avoid specifying a fixed size buffer for reading a line
use std::copy() with istream_iterator for parsing the line of integers
For example:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
int main ()
{
std::vector<int> ages;
std::ifstream inFile;
inFile.open("data.txt");
if(!inFile)
{
std::cout<<"didn't work";
std::cin.get();
exit (1);
}
std::string line;
std::getline(inFile, line);
std::istringstream in(line);
std::copy(std::istream_iterator<int>(in),
std::istream_iterator<int>(),
std::back_inserter(ages));
return 0;
}

Reading a file into an array

I would like to read a text file and input its contents into an array. Then I would like to show the contents of the array in the command line.
My idea is to open the file using:
inFile.open("pigData.txt")
And then to get the contents of the file using:
inFile >> myarray [size]
And then show the contents using a for loop.
My problem is that the file I am trying to read contain words and I don't know how to get a whole word as an element in the array. Also, let's say that the words are divided by spaces, thus:
hello goodbye
Could be found on the file. I would like to read the whole line "hello goodbye" into an element of a parallel array. How can I do that?
Should be pretty straightforward.
std::vector<std::string> file_contents;
std::string line;
while ( std::getline(inFile,line) )
file_contents.push_back(line);
std::vector<std::string>::iterator it = file_contents.begin();
for(; it!=file_contents.end() ; ++it)
std::cout << *it << "\n";
Edit:
Your comment about having "hello goodbye" as element zero and element one is slightly confusing to me. The above code snip will read each line of the file and store that as an individual entry in the array 'file_contents'. If you want to read it and split it on spaces that is slightly different.
For context, you could have provided a link to your previous question, about storing two lists of words in different languages. There I provided an example of reading the contents of a text file into an array:
const int MaxWords = 100;
std::string piglatin[MaxWords];
int numWords = 0;
std::ifstream input("piglatin.txt");
std::string line;
while (std::getline(input, line) && numWords < MaxWords) {
piglatin[numWords] = line;
++numWords;
}
if (numWords == MaxWords) {
std::cerr << "Too many words" << std::endl;
}
You can't have one parallel array. For something to be parallel, there must be at least two. For parallel arrays of words, you could use a declarations like this:
std::string piglatin[MaxWords];
std::string english[MaxWords];
Then you have two options for filling the arrays from the file:
Read an entire line, and the split the line into two words based on where the first space is:
while (std::getline(input, line) && numWords < MaxWords) {
std::string::size_type space = line.find(' ');
if (space == std::string::npos)
std::cerr << "Only one word" << std::endl;
piglatin[numWords] = line.substr(0, space);
english[numWords] = line.substr(space + 1);
++numWords;
}
Read one word at a time, and assume that each line has exactly two words on it. The >> operator will read a word at a time automatically. (If each line doesn't have exactly two words, then you'll have problems. Try it out to see how things go wrong. Really. Getting experience with a bug when you know what the cause is will help you in the future when you don't know what the cause is.)
while (input && numWords < MaxWords) {
input >> piglatin[numWords];
input >> english[numWords];
++numWords;
}
Now, if you really one one array with two elements, then you need to define another data structure because an array can only have one "thing" in each element. Define something that can hold two strings at once:
struct word_pair {
std::string piglatin;
std::string english;
};
Then you'll have just one array:
word_pair words[MaxWords];
You can fill it like this:
while (std::getline(input, line) && numWords < MaxWords) {
std::string::size_type space = line.find(' ');
if (space == std::string::npos)
std::cerr << "Only one word" << std::endl;
words[numWords].piglatin = line.substr(0, space);
words[numWords].english = line.substr(space + 1);
++numWords;
}
Notice how the code indexes into the words array to find the next word_pair object, and then it uses the . operator to get to the piglatin or english field as necessary.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
int main()
{
// This will store each word (separated by a space)
vector<string> words;
// Temporary variable
string buff;
// Reads the data
fstream inFile("words.txt");
while(!inFile.eof())
{
inFile>>buff;
words.push_back(buff);
}
inFile.close();
// Display
for(size_t i=0;i<words.size();++i) cout<<words[i]<<" ";
return 0;
}
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main ()
{
vector<string> fileLines;
string line;
ifstream inFile("pigData.txt");
if ( inFile.is_open() ) {
while ( !inFile.eof() ) {
getline(inFile, line);
fileLines.push_back(line);
}
inFile.close();
} else {
cerr << "Error opening file" << endl;
exit(1);
}
for (int i=0; i<fileLines.size(); ++i) {
cout << fileLines[i] << "\n";
}
cout << endl;
return 0;
}