I have to create a program that will output various information about 1343 runners in a marathon. I'm having to import the data from a csv spreadsheet, so I chose to use the getline function. I use simple recursion to fill a string array and then simply use recursion once more to output the data. But for some reason, it only wants to display 300 or so runners' data. Here's the code:
int main(){
string data[1344];
vector<string> datav;
string header;
ifstream infile("C:\\Users\\Anthony\\Desktop\\cmarathon.csv");
int i = 0;
if (infile.is_open()) {
for (i=0; i<=1343; i++) {
getline(infile, data[i]);
}
datav.assign(data, data+1344);
for (int i = 0; i < datav.size(); i++) {
cout << datav[i] << "\n";
}
}
}
I attempted to use a vector in hopes it would help to allocate the required memory to execute the program properly (if that is in fact the problem here).
That code yields the perfect output of runners 1045-1343. I've tried simple work arounds, such as using several for() loops to combine the output seamlessly to no avail. Any information would be appreciated.
You do not need to copy from the array to the vector. You can add to the vector directly instead. Also, it is somewhat bad practice to shadow another local variable at the outer scope.
int main(){
string line;
vector<string> datav;
string header;
ifstream infile("C:\\Users\\Anthony\\Desktop\\cmarathon.csv");
if (infile.is_open()) {
// Are you supposed to read the header line first?
getline( infile, header );
while( getline( infile, line ).good() )
datav.push_back( line );
cout << "Container has " << datav.size() << " lines\n";
for (size_t i = 0; i < datav.size(); i++) {
cout << datav[i] << "\n";
}
}
}
Of course, you still have to break down each line to the individual fields, so pushing back a class or struct as EToreo suggested would be a good idea.
You should try using a struct to represent the fields in the CSV file and then make a vector of that struct type.
Now, loop through the file, reading each line till you reach the end of the file (Google how to do that) - DO NOT assume 1343, you don't have to. When you read in each line, create a new object from your struct and fill it with the content of that line (you will need to parse it by reading till a tab (\t) or the end of the string) and then datav.push(newObj) it onto your vector.
I suggest using the correct type's in your struct (int for age, string for name, etc.) and passing the string values from the file into those types. It will be much easier to do things like make a sum of everyone's age. You will thank yourself (and maybe me?) later.
If your not needing to use a vector:
for (i=0; i<=1343; i++) {
cout << data[i] << endl;
}
should work to print out whatever is in the data array
It is also possible to specify a delimeter for the getline function if you need to put different strings in different variables.
However EToreo's method may be more useful to you in the long run.
Related
ifstream f("events.txt");
if (f.is_open())
{
string l,t;
string myArray[5];
int i = 0;
while (getline(f, l))
{
getline(stringstream(l), t, ',');
cout << t << endl;
myArray[i] = t;
cout << myArray[i] << endl;
i = i + 1;
}
So I have a file called 'events.txt' that contains:
An angry orc hits you with his weapon!,-50
A mage casts an evil spell on you!,-20
You found a health potion!,25
An enemy backstabs you from the shadows!,-40
You got eaten by a Dragon!,-1000
This part of the program so far prints out the sentence up to the comma and stores it into an array.
My problem is I also want to access the number in some way and store it into another array or to use it when the event occurs, as it'll be used to lower player HP.
Thanks in advance!
A simple way to do this:
Define a struct to store your data:
struct Event {
std::string message;
int number;
}
(Don't store both items in separate arrays, they belong together.)
Create a vector of this struct and add the items to it:
std::vector<Event> events;
while (getline(f, l)) {
size_t pos = l.find(',');
Event e;
e.message = l.substr(0, pos);
e.number = std::stoi(l.substr(pos+1));
events.push_back(e);
}
However this assumes that the string has exactly one comma. If you want to be more flexible, use std::strtok or regular expressions.
Another recommendation: Separate I/O from parsing. Don't try to read data types like int directly from the input stream, as suggested in one of the comments. Instead, read the whole line or whatever your parsing unit is and then do the parsing. This makes your code more readable and simplifies error handling and debugging.
I believe my error is within my writeline function, when I attempt to write the contents of the vector to the new file using a while loop.
//Read from txt file, write to new text file
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
void readline();
void sortline(vector<string>& sortthis);
void writeline(vector<string>& list);
int main()
{
readline();
system("pause");
return 0;
};
void readline()
{
string line;
vector<string> lines;
ifstream myfile("classes.txt");
if (myfile.is_open())
{
while (myfile.good())
{
getline(myfile, line);
lines.push_back(line);
};
myfile.close();
}
cout << "readline() has run" << endl;
sortline(lines);
writeline(lines);
};
void sortline(vector<string>& sortthis)
{
sort(sortthis.begin(), sortthis.end());
};
void writeline(vector<string>& list)
{
ofstream myfile2("new.txt");
if (myfile2.is_open())
{
int i = 0;
while(i !=list.size()-1)
{
myfile2 << list[i] << endl;
i++;
};
myfile2.close();
};
cout << "writeline() has run" << endl;
};
this is a project from a semester ago that i'm revisiting. I wrote the program on my mac, now i'm trying to run it on my windows comp with visual studio. I'll describe what I'm attempting to do, I apologize if my choice of words is terrible in advance. anywhere I put a * is where I'm not sure what is happening, but I'll take a stab at it.. any explanations of my code is very appreciated!!
my readline() function does the following: creates a string called line, creates a vector of string type called lines, **input the file classes.txt and establish myfile as it's object, then open myfile for writing, **use the while loop to write the lines from the txt into the myfile object, then close myfile, print out a statement to let the user know readline() has run, then **pass the vector called lines into the sortline function, and then pass lines into the writeline function.
** sortline takes in a vector of strings as its arg, and assigns it the object sortthis?? then I'm not sure what happens, but it looks like i applied a sorting algorithm, anybody have any thoughts?
and finally we get to my writeline function which takes in a vector of strings as its arg and assigns them the name lines (is that correct?) i then want to establish a new out file stream to a new textfile called "new.txt" with an object name myfile2, if myfile2 is open, then i want to write all the lines from the vector of strings(which contain the contents of the original text file) into myfile2, which will write them to the new.txt file, then close myfile2, print a message stating the function has run, and that is all.
The way you loop through list in writeline is not safe. You should use a for loop or a while loop with iterator. As it is, your code probably doesn't do what you intend it to do even if there are several elements in list. Consider the following:
std::vector<std::string> vLines;
vLines.push_back("Hello");
vLines.push_back("File");
vLines.push_back("World");
std::ofstream of("file.txt");
int i = 0;
while (i != vLines.size() - 1)
{
of << vLines[i] << std::endl;
++i;
}
Even with several elements in vLines, this will only actually print output 2 elements into of.
i will be 0 which is not 2, so "Hello" will be output to of.
i will be 1 which is not 2, so "File" will be output to of.
i is now 2, which is equal to 2, so "World" will not be output to of.
That's with elements. If there are 0 elements in vLines, you will be indexing out of bounds (which I suspect is what you are doing, hence your error):
std::vector<std::string> vLines;
std::ofstream of("file.txt");
int i = 0;
while (i != vLines.size() - 1)
{
of << vLines[i] << std::endl;
++i;
}
i will be 0, which is not equal to -1, so the code will run and try to output vLines[0] to of, but there is no vLines[0]! I suspect this is what you are experiencing.
This will go away if you use a proper range-based loop instead (credit to #WhozCraig for C++11 solution):
for (auto const& s : vLines)
of << s;
Or if you don't have C++11 you can still mimic a proper range-based loop with the following:
for (int i = 0; i < vLines.size(); ++i)
of << vLines[i] << std::endl;
Or an iterator:
for (auto it = vLines.begin(); it != vLines.end(); ++it)
of << *it << std::endl;
You will now output all elements in your std::vector to your std::ofstream as well as properly handle situations where there are no elements.
I am writing a code to check to see if one document (text1.txt) contains a list of banned words (bannedwords.txt) in it.
For example, the text1 document contains lyrics to a song and i want to check whether the word pig from the banned document is included in it. I then want the out put to be similar to:
"pig" found 0 times
"ant" found 3 times
This is what I have come up with so far but cannot seem to put the array of banned words into the search. Any help would be amazing :D
Thanks Fitz
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool CheckWord(char* filename, char* search)
{
int offset;
string line;
ifstream Myfile;
Myfile.open(filename);
if (Myfile.is_open())
{
while (!Myfile.eof())
{
getline(Myfile, line);
if ((offset = line.find(search, 0)) != string::npos)
{
cout << "The Word " << search<< " was found" << endl;
return true;
}
else
{
cout << "Not found";
}
}
Myfile.close();
}
else
cout << "Unable to open this file." << endl;
return false;
}
int main()
{
ifstream file("banned.txt");
if (file.is_open())//file is opened
{
string bannedWords[8];//array is created
for (int i = 0; i < 8; ++i)
{
file >> bannedWords[i];
}
}
else //file could not be opened
{
cout << "File could not be opened." << endl;
}
ifstream text1;//file is opened
text1.open("text1.txt");
if (!text1)//if file could not be opened
{
cout << "Unable to open file" << endl;
}
CheckWord("text1.txt", "cat");
system("pause");
}
Your main() function is reading the contents of banned.txt into an array of 8 std::string named bannedWords.
The array bannedWords is not being used anywhere after that. C++ doesn't work by magic, and compilers are not psychic so cannot read your mind in order to understand what you want your code to do. If an array (or its elements) are not accessed anywhere, they will not be used to do what you want with them.
You need to pass strings from the bannedWords array to CheckWord(). For example;
CheckWord("text1.txt", bannedWords[0].c_str());
will attempt to pass the contents of the first string in bannedWords to CheckWord().
However, that will not compile either unless you make the second parameter of CheckWord() (named search) be const qualified.
Or, better yet, change the type of the second argument to be of type std::string. If you do that, you can eliminate the usage of c_str() in the above.
I don't claim that is a complete solution to your problem - because there are numerous problems in your code, some related to what you've asked about, and some not. However, my advice here will get you started.
Your question is really vague; it looks like you need to spend some time to pin down your program structure before you could ask for help here.
However, since we were all new once, here's a suggestion for a suitable structure:
(I'm leaving out the file handling bits because they're irrelevant to the essential structure)
//Populate your array of banned words
std::string bannedWords[8];
int i;
for (int i = 0; i < 8; ++i)
{
file >> bannedWords[i];
}
//Load the entire file content into memory
std::ifstream in("text1.txt");
std::string fileContents((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
So now the entire file content is in the string "fileContents", and the 8 banned words are in "bannedWords". I suggest this approach because otherwise you're opening, reading, and closing the file for every word. Hardly a good design.
Now you've got to check each word against the file content. There's some more sophisticated ways to do this, but your simplest option is a loop.
//Loop through each banned word, and check if it's in the file
for (int i = 0; i < 8; i++)
{
if (fileContents.find(bannedwords[i]) != std::string::npos)
{
//Do whatever
}
}
Obviously you'll need to do the find a little differently if you want to count the number of occurrences, but that's another question.
I am writing a program that extracts data from a text file and encrypts it. I am having some trouble with this. First of all there is an error at the getline(data,s[i]) part. Also the text file has two sentences but it only encrypts the second sentence. The other issue with that is It encrypts one letter at a time and outputs the sentence every time. It should output just the sentence encrypted.
#include <iostream>
#include <fstream>
#include <istream>
using namespace std;
int main(){
//Declare Variables
string s;
ifstream data;
//Uses Fstream to open text file
data.open ("/Users/MacBookPro/Desktop/data.txt");
// Use while loop to extract the data from the text file
while(!data.eof()){
getline(data,s);
cout<< s << endl;
}
//Puts the data from the text file into a string array
for(int i = 0; data.good(); i++){
getline(data, s[i]);
cout<< s <<endl;
}
// encrypts the string
if(data.is_open()){
for(int i = 0; i < s.length();i++){
s[i] += 2;
cout << s << endl;
}
}
return 0;
}
In the code below you already reach the end of the stream, and store the last line on the string s.
while(!data.eof()){
getline(data,s);
cout<< s << endl;
}
My suggestion is that you use a list of strings.
vector< string > s;
string tmp;
while(!data.eof()){
getline(data,tmp);
s.push_back(tmp);
cout<< s << endl;
}
The next step you loop through the list and do the encryption
for(i=0; i < s.size(); i++)
{
// encrypt s[i]
}
Hope this helped!
First I had to add this line to get "getline" to be recognised:
#include <string>
Then, there was indeed an error with the line:
getline(data, s[i]);
This is a compilation error, that function is expecting a stream and a string, but you pass it a stream and a char.
Changing that line for:
getline(data, s);
makes your program compile.
However it probably does not do what you want at this point, since the variable i from the for is being ignored.
I suggest that you check out some documentation on the getline function, then rethink what you want to do and try again.
You can fine some doc here:
https://msdn.microsoft.com/en-us/library/vstudio/2whx1zkx(v=vs.100).aspx
Your other concern was that it output your string many times. This is normal, since your cout statement is inside in your encryption loop.
Move it outside the loop instead, to output it only one time once the encryption loop is done.
It is important to spend the time to understand what each line of your program is doing, and why you need it to achieve your goal.
Also when doing something that we find complicated, its easier to do one small part of it at a time, make sure it works, then continue with the next part.
Good Luck :)
Create a temporary string for containing each line and an integer since we're going to find the total number of lines to create an array for all of them.
string temp = "";
int numberOfLines = 0;
Now we try to find the total number of lines
while(data.good()) {
getline(data, temp);
cout << temp << endl;
numberOfLines++;
}
Now we can create an array for all of the lines. This is a dynamic array which you can read on it for more information.
string * lines = new string[numberOfLines];
Now is the time to roll back and read encrypt all the lines. But first we have to go back to first position of file. That's why we use seekg
data.seekg(data.beg);
For each line we read, we'll put in the array and loop through each character, encrypt it and then show the whole sentence.
int i = 0;
while (data.good()) {
getline(data, lines[i]);
i++;
for (int j = 0; lines[i].size(); j++ ) {
lines[i].at(j) += 2;
}
cout << lines[i] << endl;
}
Voila!
s[i] is a character in the string (actually, a character reference), not the string object itself. string::operator[] returns a char& in the docs. See here.
Consider declaring a std::vector<string> string_array; and then use the string_array.push_back(data) member function to append strings from the file onto the vector. Use a for loop to iterate through the vector at a later time with a vector<string>::iterator or the std::vector::size function to get the length of the vector for a traditional for loop (via a call to string_array.size()). Use the square brackets to get each string from the vector (string_array[0 or 1 or etc.]).
Get characters from each string in the vector by using something like string_array[n][m] for the mth character of the nth string. Iterating over each character should be as simple as using the string::length member function to get the string length, and then another for loop.
Also, std::cout << s << std::endl is being used in the wrong places. To output each character, try std::cout << s[i] << std::endl instead, or printf("%c", s[i]), whichever you like.
I'd suggest not using an array to hold strings from the file because you don't know what the array's length will be at runtime (the file size could be unbounded), so a vector is better suited for this case.
Finally, if you need code, there's a beginner's forum post here that I think will help you out. It has a lot of code like yours, but you'll have to modify it for your purposes.
Finally, please use:
std::someCPPLibraryFunction(args);
instead of...
using namespace std;
someCPPLibraryFunction(args);
I've been trying to retrieve saved data from a text file. The data stored are both numbers, separated by a ~. I've managed to get it to print out one of the lines (the top line) however I've been unable to figure out how to proceed through the entire file.
There are only two numbers (integers) on each line, an X and Y position of another vector. The idea is to assign each integer to the respective variable in the vectors. I've not managed to get that far since I can't get it to go past line 1. But I'd thought that by having an array size of 2, and the array temporarily stores the value, assigns it to the vector, then overwrites it with the next value(s) that could work. But again not managed to get that far.
Below is the code I've been trying to use;
........
string loadZombieData;
loadFile >> loadZombieData; //Data gets read from the file and placed in the string
vector<string> result; //Stores result of each split value as a string
stringstream data(loadZombieData);
string line;
while(getline(data,line,'~'))
{
result.push_back(line);
}
for(int i = 0; i < result.size(); i++){
cout << result[i] << " ";
}
.......
Just to clarify, this is not my code, this is some code I found on Stackoverflow, so I'm not entirely certain how it all works yet. As I said, I've been trying to get it to read multiple lines, then using the for loop was going to assign the results to the other vector variables as needed. Any help is appreciated :)
Use two while loops:
std::vector<std::string> result;
std::vector<int> numbers;
std::string filename;
std::ifstream ifile(filename.c_str());
if (!ifile.is_open()) {
std::cerr << "Input file not opened! Something went wrong!" << std::endl;
exit(0);
}
std::string temp;
//loop over the file using newlines as your delimiter
while (std::getline(ifile, temp, '\n')) {
//now temp has the information of each line.
//create a stringstream initialized with this information:
std::istringstream iss(temp);//this contains the information of ONE line
//now loop over the string stream object as you would have in your code sample:
while(getline(iss, temp,'~'))
{
//at this point temp is the value of a token, but it is a string
result.push_back(temp); //note: this only stores the TOKENS as strings
//so to store the token as a int or float, you need to convert it to that
//via another stringstream:
std::istringstream ss(temp);
//if your number type is float, change it here as well as in the vector
//initialization of `numbers`:
int num = 0;
//this checks the stream to ensure that conversion occurred.
//if it did, store the number, otherwise, handle the error (quit - but, this is up to you)
//if stringstreams aren't your cup of tea, try some others (refer to this link):
//http://stackoverflow.com/questions/21807658/check-if-the-input-is-a-number-or-string-c/21807705#21807705
if (!(ss >> num).fail()) {
numbers.push_back(num);
}
else {
std::cerr << "There was a problem converting the string to an integer!" << std::endl;
}
}
}
Note: this version stores the numbers verbatim: i.e. without a sense of how many numbers were on a line. However, that is reconcilable as all you have to do is output n numbers per line. In your case, you know every 2 numbers will be represent the numbers in a line.
This requires:
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>