if (infile.is_open())
{
int count = 0;
while (infile)
{
string author, ratings;
getline(infile, author);
if (author != "")
{
getline(infile, ratings);
// TODO: Create new User object
User newuser(author, ratings);
// TODO: Add new User object to vector
userList.push_back(newuser);
count++;
}
}
cout << count << " users read in. Closing user file." << endl;
The output for this that I am getting is that 86 users were read in from the text file. the correct output is supposed to be 32. I think that it is because I am using a while loop but I am not fully sure.
Your condition should be something like
while (getline(author, infile) && getline(ratings, infile)) {
// validate input, then process it
}
Then the if (infile.open()) becomes trivial. There is a '}' missing in the code you posted, which makes it hard to really tell where your counting error is coming from, or maybe that's just the reason, incrementing your count in the wrong place. Please make sure your examples are complete and possibly even compile.
A little tip, you can just write
userList.push_back(User(author, ratings));
EDIT:
I created this minimal test code (for you) and tested it on the following file, resulting in the following output. Can you confirm? Please note: The current program doesn't accept newlines in your file, e.g. for grouping various users, however, this is a feature easily added, once the basic program works.
Code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
struct User {
string author, ratings;
User(string auth, string rat)
: author(auth), ratings(rat) {}
};
int main()
{
ifstream ist("test.txt");
if (!ist) {
cout << "Could not open file test.txt\n";
return 1;
}
vector<User> userList;
string author, ratings;
size_t count = 0;
while (getline(ist, author) && getline(ist, ratings)) {
if (author != "" && ratings != "") {
userList.push_back(User(author, ratings));
++count; // in this case, count++ is equivalent
}
}
cout << count << " users read in. Closing user file.\n";
}
The file test.txt
foo
bar
foobar
lalilu
myTotalUsersAre
3
Output:
3 users read in. Closing user file.
Related
I'm new to C++ and stackoverflow so forgive me any mistakes in my post ;). I need to create a code, which allows me to fill new objects with data from std::cin and export these objects to binary file later. Also, I need to import objects exported to file at some point. Objects represent users with standard user information like username, ID, lvl etc.
#include <vector>
#include <string>
#include <iostream>
class User {
std::string username;
unsigned int ID, lvl;
public:
User(std::string un, int uID, int ulvl) {
username = un;
ID = uID;
lvl = ulvl;
}
};
int main() {
std::string u_name;
int u_ID,u_lvl;
bool finish = false;
char choice;
std::vector<User> test_user_vec;
do {
std::cout << "Enter username: ";
std::cin >> u_name;
std::cout << "Enter ID: ";
std::cin >> u_ID;
std::cout << "Enter lvl: ";
std::cin >> u_lvl;
test_user_vec.push_back(User(u_name, u_ID, u_lvl));
std::cout << "Do you want to add another user? (y/n)?";
choice = getch();
if (choice == 'y') finish = true;
} while (!finish);
return 0;
}
I assume that test_user_vec stores every object I created while my program is running. My problem occurs when I want to export that vector to file. The purpose of this action is to store objects' data even after my program terminates and import all the data when I run my program again.
I was trying to solve this problem on my own, nothing really came to my mind. While I was looking for some info i found something like this:
#include <fstream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> v{ "one", "two", "three" };
std::ofstream outFile("my_file.txt");
// the important part
for (const auto &e : v) outFile << e << "\n";
}
I've tested it with <string> and <int> vectors and my variables. It's good until I try to export <object>vector.
Also i found another solution and tried to do something with it on another test code:
class Test {
public:
int number;
float number2;
};
int main(){
Test test1;
test1.number = 122;
test1.number2=12;
std::fstream testfile("test1.bin", std::ios::out | std::ios::binary);
testfile.write((char*)&test1, sizeof(test1));
testfile.close();
//ater writing an object with variables i commented this section
//then uncommented this section and run the program again
std::fstream testfile2("test1.bin", std::ios::in);
testfile2.read((char*)&test1, sizeof(test1));
std::cout << test1.number;
testfile2.close();
return 0;
}
Again, it works, i can read test1.number until I want to use vector of objects, not a single object. With vector of objects my cout printed some random values like 11314123e-03.
I was trying to somehow combine these 2 solutions, but nothing worked out. I would like to have a binary file, because i heard it's faster and has any data protection (i can't just open it in notepad and read the data) I'm new to c++, there is a great chance of me trying to do it reeeeeealy inefficient way, so pls help :D.
Data member getter functions can be added to the User class and used in fstream output operations. This should provide the general idea:
std::string userName;
for (const auto &u : v)
{
outFile.write(u.GetID(), sizeof(int));
outFile.write(u.GetLvl(), sizeof(int));
userName = u.GetName();
outFile.write(username.length(), sizeof(size_t));
outFile.write(userName.data(), username.length());
}
For userName, the length is written to precede the userName string data in the file so that the file can be parsed when read. The binary encoding/convention is designer's decision as there are several options. Another option would be to encode the entire object as a null-terminated string, although this would generally be less size efficient except for the userName string itself.
Note: test_user_vec.push_back(User(u_name, u_ID, u_lvl)); is creating temporary User objects on the stack. As #drescherjm and #RaymondChen pointed out, that is OK, but this is a better alternative: test_user_vec.emplace_back(...);
i want to take a film name from user and change that to camel case , my code work if there is no numbers or spaces between letters
#include <iostream>
#include <string>
using namespace std;
int main()
{
int Count,Length=0;
string Films;
cout<<"Enter Film Count: ";
cin>>Count;
for(int i=0;i<Count;i++)
{
cout<<"Enter Film Names: ";
cin>>Films;
Length=0;
while(Length<1000)
{
switch(Length)
{
case 0: Films[Length]=toupper(Films[Length]); break;
default: Films[Length]=tolower(Films[Length]); break;
}
Length++;
}
cout<<"Results: "<<Films<<endl;
}
return 0;
}
i tried other topic solutions but i cant do it correctly.
Problem:
You've chosen the wrong approach to solve the problem. Your current code only changes the first character to uppercase and the rest to lowercase.
Solution:
Instead of using a while and a switch, use a for loop and an if statement that checks for spaces, delete them and change the following characters to uppercase.
Additional information:
using namespace std; is considered a bad practice (More info here).
The while loop can be replaced for a for loop to limit the Length scope and improve readability.
It's a good practice to check whether the std::cin inputs are valid or not to prevent Undefined Behavior.
Full code:
#include <iostream>
#include <string>
int main()
{
int count;
std::cout << "Enter film count: ";
std::cin >> count;
if(std::cin.fail())
{
std::cout << "Invalid input." << std::endl;
exit(0);
}
std::cin.ignore(10000,'\n');
for(int i = 0; i < count; i++)
{
std::string film;
std::cout << "Enter film name: ";
std::getline(std::cin, film);
if(std::cin.fail())
{
std::cout << "Invalid input." << std::endl;
exit(0);
}
if(film.size() == 0)
break;
film[0] = tolower(film[0]);
for(unsigned int i = 1; i < film.size() - 1; i++)
{
if(film[i] == ' ')
{
film.erase(i,1);
film[i] = toupper(film[i]);
i--;
}
}
std::cout << "Result: " << film << std::endl;
}
return 0;
}
Example:
Enter film count: 1
Enter file name: Love live! the school idol movie
Result: loveLive!TheSchoolIdolMovie
I could see really a lot of code to solve a simple problem. I will later show a one-liner that converts a string with words to camel case.
As a side note, code should always contain tons of comments. Otherwise, nobody will understand it, and later, even you will not understand your own code.
Anyway. Let us look at the requirements. What shall we do?
User shal input the number of film titles to convert
Title for title shall be read from the user
Titles have to converted to camel case style and shown to the user
Now, we think an how we want to solve the problem:
We will always instruct the user what to do next
We will make sanity checks for the users input
We will get the number of titles from the user
Then, we create a loop and read title for title
The current read title will be converted to camel case
The result will be shown to the user
Ok, we need to go into details for "The current read title will be converted to camel case"
Let us think again. We get a string, that consists of words. So, we need to extract words from the string. We consider that everything is a word, that is separated by white space.
Then, depending on the camle case style, please see here, we convert all first letters of a word to uppercase and discard all white spaces. The first word will have a starting lower case letter (selectable).
But how to extract words from a string? We remember the extractor operator >> will discard all white spaces and only read the text. That is what we need. So, we will pack the string into an std::istringstream and then extract word for word.
And with a simple boolean condition, we decide, if the first letter of the first word shall be in upper- or lower case.
So, let us implement or thoughts into code:
#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
int main() {
// Instruct user, what to do
std::cout << "\nPlease end number of film titles to convert: ";
// Read input from the user and check, if that was valid
if (size_t numberOfFilms{}; std::cin >> numberOfFilms && numberOfFilms > 0) {
// Now, in a loop, read all the film titles that the user wants to be processed
for (size_t index{}; index < numberOfFilms; ++index) {
// Instruct user, what to do
std::cout << "\n\nPlease end film title " << index + 1 << ": \t";
// Read a complete line and check, if that worked
if (std::string line{}; std::getline(std::cin >> std::ws, line)) {
// Put the complete string into an istringstream, so that we can extract the words
std::istringstream lineStream{line};
// Here we can select the style of our camel case
bool wordShallHaveFirstLetterInUpperCase{ false };
// Extract all words from the line stream and convert first letter
for (std::string word{}; lineStream >> word; std::cout << word) {
// Depending on the camel case style
if (wordShallHaveFirstLetterInUpperCase)
word[0] = std::toupper(word[0]);
else
word[0] = std::tolower(word[0]);
// From now on all words shall start with an uppercase character
wordShallHaveFirstLetterInUpperCase = true;
}
}
else std::cerr << "\n\n*** Error: Problem while a title\n\n";
}
}
else std::cerr << "\n\n*** Error: Problem while reading the number of ilm titles\n\n";
return 0;
}
This is a rather straight forward implementation of our detailed design. And after running some tests, we see that it will work.
Now, for the more advanced users.
In professional software development, people try to avoid loops and branch statements. Because this will increase the code complexity (usually measured via the cyclomatic complexity). And complex code needs more tests cases for C0, C1 or even MCDC code coverage.
Therefore, often algorithms from the standard library are used. And they hide the loops somehow inside. But that is OK, because the standard library is thoroughly tested and sometimes even qualified with a certification.
So, as one example, you can do the whole camel case conversion with one statement. With std::transform and by using std::regex and iterators and a stateful Lambda.
The downside is, that it is not so easy to understand for the reader . . .
Please see yourself:
#include <iostream>
#include <iterator>
#include <algorithm>
#include <regex>
#include <string>
#include <cctype>
// The separator will be white space
const std::regex re{ R"(\s+)" };
int main() {
// Instruct user, what to do
std::cout << "\nPlease end number of film titles to convert: ";
// Read input from the user and check, if that was valid
if (size_t numberOfFilms{}; std::cin >> numberOfFilms && numberOfFilms > 0) {
// Now, in a loop, read all the film titles that the user wants to be processed
for (size_t index{}; index < numberOfFilms; ++index) {
// Instruct user, what to do
std::cout << "\n\nPlease end film title " << index+1 << ": \t";
// Read a complete line and check, if that worked
if (std::string line{}; std::getline(std::cin >> std::ws, line)) {
// Convert to camel case and show output
std::transform(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {}, std::ostream_iterator<std::string>(std::cout),
[firstIsUpper = 0U](std::string s) mutable {if (firstIsUpper++) s[0] = std::toupper(s[0]); else s[0] = std::tolower(s[0]); return s; });
}
else std::cerr << "\n\n*** Error: Problem while a title\n\n";
}
}
else std::cerr << "\n\n*** Error: Problem while reading the number of ilm titles\n\n";
return 0;
}
Ultra compact, but difficult to read . . .
In case of questions, please ask.
I'm trying to make a ticket customer code, and I'm currently working with displaying my "customers". I want it to be like, if i type "blank, like nothing then enter" I want all of my customers in my own DTA file to be on my output. In other words displayed, to see which customers are registered.
void Customer::DisplayCustomer() {
cin.getline(buffer, MAXTEXT)
buffernr = atoi(buffer) //I need to convert text to numbers.
if (buffer[0]=='A' && buffer[1] == '\0')
// (Here I have a function which displays everything) don't focus on this one
}
What I'm asking is, what do i have to type, in order for my code to understand that I want to have a if statement for someone who presses Enter without typing anything my display customer function will run. I've also tried (If buffer[0]=='\n') but that won't work either.
It seems you want to use std::getline() rather than std::istream::getline() for your use case:
void Customer::DisplayCustomer() {
std::string buffer;
std::getline(std:cin,buffer);
std::istringstream iss(buffer);
int buffernr;
if(!(iss >> buffernr)) { // This condition would be false if there's no numeric value
// has been entered from the standard input
// including a simple ENTER (i.e. buffer was empty)
// (Here i have a function which displays everything) don't focus on this
// one
}
else {
// Use buffernr as it was parsed correctly from input
}
}
This code checks if the buffer is empty
#include <iostream>
int MAXTEXT{300};
int main() {
char buffer[MAXTEXT];
std::cin.getline(buffer, MAXTEXT);
if (buffer[0] == '\0') {
std::cout << "Empty" << std::endl;
}
return 0;
}
A better solutions with std::string is
#include <string>
#include <iostream>
int main() {
std::string buffer;
std::getline(std::cin, buffer);
if (buffer.empty()) {
std::cout << "Empty" << std::endl;
}
return 0;
}
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.
For an assignment of mine, we're suppose to take in several lines of input from the keyboard. For example:
Please enter your name: (this is static. Always 1 input)
Justin
Please enter the names: (this can be any number of inputs, smallest being 1)
Joe
Bob
John
Jackson
In the end, I want to compare the named entered at the beginning with all of the names entered in after. I tried using getline and cin, but that seems to only work if I know the exact number of names I expect to be entered. Can anyone guide me in the right direction please. Thank you
Try this
void read_lines( std::istream& in, std::list< std::string >& list ) {
while( true ) {
std::string line = "";
std::getline( in, line );
if( line != "" ) {
list.push_back( line );
} else {
break;
}
}
}
You should have added some rough code showing your efforts on doing the assignment.
However, I will provide you with some initial naive code (please read the comments inside!):
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string name, temp;
vector<string> names; // this is just one of the possible container that you can use
bool result = false; // flag used to store the result of the matching operation (default: false)
// first we ask the user to enter his/her name
cout << "Please enter your name:" <<endl;
cin >> name;
// then we need something a little bit more complicated to look for variable number of names
cout << "Please enter the names:" <<endl;
while(cin)
{
cin >> temp;
names.push_back(temp);
}
// This for-loop is used to go through all the input names for good-match with the user name
for( int i = 0; i < names.size(); i++ )
{
temp = names.front();
if (name == temp) result = true; // change the flag variable only in case of match
}
cout << "Valid match: " << (result?"yes":"no"); // ternary operator
}
You did not provide in your question enough details.. so the above code may not fully fit your requirements!