Given a method that I wrote on my own, a text file is given and I want to save the items into a vector<Object> referenceObject. It works nearly, but if I got in my text file objects like, for example: " Book of light ", it just saves "Book", so it stops reading on the first space.
I read some other StackOverflow questions like mine, but for my problem they don't work.
Question: It returns all objects of my text file, except for my first object. So my list starts by index=1 and not by index=0. Why?
void openfile() {
ifstream inFile;
inFile.open("textfile");
if (inFile.fail()) {
cerr << "error open this file" << endl;
exit(1);
}
string item;
int count = 0;
vector<Object> referenceObject;
while (!inFile.eof()) {
while (getline(inFile, item)) {
inFile >> item;
Object s;
s.setName(item);
referenceCards.push_back(s);
std::cout << count << ' ' << referenceObject.at(count).getName() << endl;
count++;
}
}
When you do this:
while (getline(inFile, item)) { // reads line into item
inFile >> item; // overwrites item
// ... // do stuff with item
}
You are reading the first line, and then immediately ignoring it (by overwriting it with the first string up to the space from the second line).
Instead, simply do this:
while (getline(inFile, item)) { // read line into item
// ... // do stuff with item
}
Also, avoid this check:
while (!inFile.eof())
See Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong? for why it's recommended against.
Related
I have just a couple issues here with my code. It works but I'm not advanced enough to do what I want to yet. Nor do I know how to word it for a google search. I have a Blackjack game that I'm doing and want to know how to edit certain lines of the file depending on user input. Simpler, I want a user to be able to open the game and start with their balance from the last time they were playing(a save and load feature). My issues are the balance and the username are on the same line in the text file (purposefully) and I want to assign the variables to those in the text file. I know I'm on the right track, I just dont know where to go from here. Thanks for the help in advance. If I broke a rule of posting, I'm sorry.
input username
if username is present in file
edit balance on leave
if username isnt present in file
create new user
Here is my code for the load function:
void load(userAcc user1)
{
ifstream in;
in.open("Balances.txt");
if (in.is_open())
{
string word;
for (int x = 0; in >> word; x++);
{
user1.name = word;
user1.balance = word;
}
cout << user1.name << endl;
cout << user1.balance << endl;
in.close();
}
else
cout << "Cannot open a file";
}
void save(userAcc user1)
{
user1.balance = "1000";
cout << "Enter a username: ";
cin >> user1.name;
ofstream out;
out.open("Balances.txt", ios_base::app);
if (out.is_open())
{
out << user1.name << " " << user1.balance << endl;
out.close();
}
else
cout << "Cannot open a file";
}
In
for (int x = 0; in >> word; x++);
remove the trailing ;. It ends the statement before the body of the for loop, separating the two. The for spins around doing nothing but reading the file until it ends and incrementing the unused variable x and the following code block will be run exactly once, storing whatever is in word (and since the loop will exit when the read into word fails, what's in word will depend on the C++ Standard version the the compiler's been set to use) into user1.
Once the ; is removed, the for loop will read into word until no more words can be read from the file. Every word read is copied into the same userAcc writing over the previous word. When the file hits the end in >> word will fail and the loop will exit. The last word in the file will then be printed out, all other words having been overwritten.
Naïve fixing of this would look something like
void load(userAcc user1)
{
ifstream in;
in.open("Balances.txt");
if (in.is_open())
{
while (in >> user1.name // read name in from file
>> user1.balance) // read balance in from file
{ // loop will exit when it cannot read a name and a balance from the file
// for now we're just printing out what's read from the file.
cout << user1.name << endl << user1.balance << endl;
}
// in.close(); not needed. File will automatically close when in goes out of scope.
}
else
cout << "Cannot open a file";
}
But we probably want to do more than print out all of the users in the file, so let's put them into a convenient resizable container like std::vector.
vector<userAcc> load() // takes no parameters, returns list of accounts
{
vector<userAcc> accounts;
ifstream in;
in.open("Balances.txt");
if (in.is_open())
{
userAcc user1; // account we can read into
while (in >> user1.name >> user1.balance)
{
accounts.push_back(user1); // store account
}
}
else
cout << "Cannot open a file";
return accounts; // hand accounts read back to caller.
}
Use of the function would be something like
vector<userAcc> accounts = load();
The save function looks pretty much good-to-go as written.
I am working on a program that should read from a file and store the contents of that file in a vector. I must read the contents of the .txt file and push the strings back into a vector before it reaches a ' '. If it is a space you will skip that part of the file and continue pushing back the contents after the space. Does anybody know what function to use to read from a file and put the contents into a vector or array? Thanks for your time.
int main()
{
Code mess;
ifstream inFile;
inFile.open("message1.txt");
if (inFile.fail()) {
cerr << "Could not find file" << endl;
}
vector<string> code;
string S;
while (inFile.good()) {
code.push_back(S);
}
cout << mess.decode(code) << endl;
return 0;
}
Basically you can also do it like this :
std::ifstream fh("text.txt");
std::vector<std::string> vs;
std::string s;
while(fh>>s){
vs.push_back(s);
}
for(int i=0; i<vs.size(); i++){
std::cout<<vs[i]<<std::endl;
}
You should change your reading code to
while (inFile >> S) {
code.push_back(S);
}
Your current code doesn't read anything into your S variable.
Regarding loop conditions while (inFile.good()) see this Q&A please:
Why is iostream::eof inside a loop condition considered wrong?
Using std::iostream::good() has more or less the same issues.
So I'm having trouble grabbing a word from document1 and comparing it to the list of words in document2. So when I run the program, the first word of document1 is comparing to the list of words of document2, but the next word in document1 isn't comparing to the list in document2. I'm not sure what the problem is... Does it have something to do with the .eof() function?
string typedString, actualString, document1 = "A.txt", document2 = "Dictionary.txt";
ifstream observeDoc, actualDoc;
observeDoc.open(document1);
actualDoc.open(document2);
while (observeDoc.is_open())
{
while (true)
{
observeDoc >> typedString;
if (observeDoc.eof()) break;
cout << typedString << endl;
while (true)
{
actualDoc >> actualString;
if (actualDoc.eof())
{
actualDoc.open(document1);
break;
}
cout << '\t' << actualString << endl;
}
}
if (observeDoc.eof()) break;
}
observeDoc.close();
actualDoc.close();
OUTPUT:
You need to go back to the beginning of the file.
you can use: observeDoc.seekg(0,ios::beg);
A better solution is to read all the words of the 1st file to an object from type std::set<std::string>, and for each word in the 2nd file check for existence in the set. In this way you move just once on each file, and no need to rewind.
std::set<std::string> words;
observeDoc.open(document1);
while (observeDoc >> typedString){
words.insert(typedString);
}
observeDoc.close();
actualDoc.open(document2);
while(actualDoc >> actualString){
if (words.find( actualString )!= words.end()){
//word exists in observer doc!
}
}
actualDoc.close();
Your problem is that actualDoc isn't resetting properly at the end of your loops. Also, your loop syntax could be way cleaner. Try this:
string typedString, actualString, document1 = "A.txt", document2 = "Dictionary.txt";
ifstream observeDoc, actualDoc;
observeDoc.open(document1);
actualDoc.open(document2);
// Will stop when it reads in EOF
while (observeDoc >> typedString)
{
while (actualDoc >> actualString)
{
// Do your comparisons here
}
actualDoc.open(document2); //reset actualDoc to start from the beginning of the file
// or, as #SHR recommended, use observeDoc.seekg(0,ios::beg);
}
observeDoc.close();
actualDoc.close();
I'm trying to read a text file to find how many times a phrase/sentence(/substring?) occurs. I've done a real bodge job on it currently (see code below) but as you'll see, it relies on some rather clunky if statements.
I don't have access to the files I''ll be using it on at home, so I've used a file called big.txt and search for phrases like "and the" for the time being.
Ideally, I'd like to be able to search for "this error code 1" and it return the number of times it occurs. Any ideas on how I might get my code to work that way would be incredibly useful!
int fileSearch(string errorNameOne, string errorNameTwo, string textFile) {
string output; //variable that will store word from text file
ifstream inFile;
inFile.open(textFile); //open the selected text file
if (!inFile.is_open()) {
cerr << "The file cannot be opened";
exit(1);
}
if (inFile.is_open()) { //Check to make sure the file has opened correctly
while (!inFile.eof()) { //While the file is NOT at the end of the file
inFile >> output; //Send the data from the file to "output" as a string
if (output == errorNameOne) { //Check to look for first word of error code
marker = 1; //If this word is present, set a marker to 1
}
else if (marker == 1) { //If the marker is set to 1,
if (output == errorNameTwo) { //and if the word matches the second error code...
count++; //increse count
}
marker = 0; //either way, set marker to 0 again
}
}
}
inFile.close(); //Close the opened file
return count; //Function returns count of error
}
Given that your phrase can only occur once per line and the number follows the phrase after a number of spaces you can read the file line by line and use std::string::find() to see of your phrase is somewhere in the line. That will return the position of the phrase. You can then work on checking the rest of the line immediately after the phrase to test the number for 1 or 0.
This code may not be exactly what you want (still not certain of the exact specs) but hopefully it should contain enough examples of what you can do to achieve your goal.
// pass the open file stream in to this function along with the
// phrase you are looking for and the number to check
int count(std::istream& is, const std::string& phrase, const int value)
{
int count = 0;
std::string line;
while(std::getline(is, line)) // read the stream line by line
{
// check if the phrase appears somewhere in the line (pos)
std::string::size_type pos = line.find(phrase);
if(pos != std::string::npos) // phrase found pos = position of phrase beginning
{
// turn the part of the line after the phrase into an input-stream
std::istringstream iss(line.substr(pos + phrase.size()));
// attempt to read a number and check if the number is what we want
int v;
if(iss >> v && v == value)
++count;
}
}
return count;
}
int main()
{
const std::string file = "tmp.txt";
std::ifstream ifs(file);
if(!ifs.is_open())
{
std::cerr << "ERROR: Unable to open file: " << file << '\n';
return -1;
}
std::cout << "count: " << count(ifs, "Header Tangs Present", 1) << '\n';
}
Hope this helps.
I've been working on some code for a file parser function to learn some C++:
It's supposed to read in this text file:
>FirstSeq
AAAAAAAAAAAAAA
BBBBBBBBBBBBBB
>SecondSeq
TTTTTTTTTTTTTT
>ThirdSequence
CCCCCCCCCCCCCC
>FourthSequence
GGGGGGGGGGGGGG
and print out the names (lines with '>' at the start) and then the sequences.
However from the output:
AAAAAAAAAAAAAABBBBBBBBBBBBBB
TTTTTTTTTTTTTT
CCCCCCCCCCCCCC
FirstSeq
SecondSeq
ThirdSequence
FourthSequence
We see that the final line of G characters is not included. The code is below. What it does is loop over lines, if it finds a name, appends it to the vector of names, if it finds a sequence, appends it to a temporary string (incase the sequence is more than one line, like the first sequence), then when it finds the name of the next sequence, stores the built up temporary string in a vector and then proceeds by overwriting the temporary string and starting again. I suspect that it is because in the while loop of the function: The line fullSequence.push_back(currentSeq); which is called whenever a new name was detected previously to push the old temp string onto the vector would not be called for the last line of G's and so it is not being included, although the name "FourthSeq" is recorded, rather the line of G's is read into the temporary string, but then is not passed to the vector. So, how can I make it so as I can detect that this is the last line of the file and so should make sure the temporary string is pushed onto the vector?
Thanks,
Ben.
CODE:
#include<fstream>
#include<iostream>
#include<string>
#include<vector>
void fastaRead(string fileName)
{
ifstream inputFile;
inputFile.open(fileName);
if (inputFile.is_open()) {
vector<string> fullSequence, sequenceNames;
string currentSeq;
string line;
bool newseq = false;
bool firstseq = true;
cout << "Reading Sequence" << endl;
while (getline(inputFile, line))
{
if (line[0] == '>') {
sequenceNames.push_back(line.substr(1,line.size()));
newseq = true;
} else {
if (newseq == true) {
if(firstseq == false){
fullSequence.push_back(currentSeq);
} else {
firstseq = false;
}
currentSeq = line;
newseq = false;
} else {
currentSeq.append(line);
}
}
}
//Report back the sequences and the sequence names...
for ( vector<string>::iterator i = fullSequence.begin(); i != fullSequence.end(); i++) {
cout << *i << endl;
}
for ( vector<string>::iterator i = sequenceNames.begin(); i != sequenceNames.end(); i++) {
cout << *i << endl;
}
cout << fullSequence.size() << endl;
cout << sequenceNames.size() << endl;
inputFile.close();
} else {
perror("error whilst reading this file");
}
if(inputFile.bad()){
perror("error whilst reading this file");
}
}
int main()
{
cout << "Fasta Sequence Filepath" << endl;
string input = "boop.txt";
fastaRead(input);
return 0;
}
Getline() will "fail" when it finds an EOF in the line, so the last line you read will not go through your loop.
I've solved this problem two ways, either by having two flags or just by processing the last line after the loop.
For two flags, the loop requires both to be true, you set one to false when getline() fails, and you set the other one to false if the first one is false, this gives you one extra loop after EOF.
Good luck!