Weird character when displaying data from .dat file in c++ - c++

I have an ipk.dat file containing student name and their GPA separated by semicolon. I'm trying to display the names of students who have a GPA greater than 3, but I get output with strange characters like this in the console.
Hidayat Sari 3.60
Susila Buana 3.27
Krisna Sari 3.66
Taufik Fatimah 3.38
Bachtiar Darma 3.70
Yohanes Anwar 3.93
Harun Ratna 3.48
Mega Zulfikar 3.32
Zulfikar Abdul 3.50
Rahman Nirmala 3.37
Amir Cinta 3.30
Firdaus Latifah 3.16
Annisa Ali 3.65
Eka Yuliana 3.14
This is my code:
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main() {
ifstream inGPA;
string studentGPA;
string studentName;
inGPA.open("ipk.dat");
if (inGPA.is_open()) {
string line;
while (getline(inGPA, line)) {
stringstream ss(line);
getline(ss, studentName, ';');
getline(ss, studentGPA);
if ( stod(studentGPA) >= 3.0) {
cout << studentName << " \t" << studentGPA << endl;
}
}
}
return 0;
}
And this is the inside of the ipk.dat file.The encoding for this file is UTF-8.
How do i fix this weird character issue?

The non-breaking space might be unwanted input, but if you have names with non-ASCII characters, you will have the same problem.
Part of the problem here is that your terminal doesn't know that you are sending UTF-8 encoded characters.
If you are on Windows you can refer to this question.
The basic idea is to set the terminal to understand UTF-8 first:
#include <Windows.h>
int main() {
SetConsoleOutputCP(CP_UTF8); // set output to UTF-8
// your code
}
This will print your non-breaking space characters normally.
Note: This change doesn't only last for the execution of your program.
If you run your unfixed program after your fixed one, the program will seemingly work, until you run it in a fresh terminal.

Since you have already fixed your issue(which seem to with the input file rather than with the program), i want to propose one modification to ͟r͟e͟m͟o͟v͟e͟ ͟t͟h͟e͟ ͟r͟e͟d͟u͟n͟d͟a͟n͟c͟i͟e͟s͟. In particular, you don't need
//no need for these three statements
stringstream ss(line);
getline(ss, studentName, ';');
getline(ss, studentGPA);
in your program. Instead you can just directly use getline on studentName and studentGPA as shown below.
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main() {
ifstream inGPA;
string studentGPA;
string studentName;
inGPA.open("input.txt");
if (inGPA.is_open()) {
string line;
//just getline directly into variables studentName and studentGPA
while (getline(inGPA, studentName, ';'), getline(inGPA, studentGPA)) {
if ( stod(studentGPA) >= 3.0) {
cout << studentName << " \t" << studentGPA << endl;
}
}
}
return 0;
}

Related

Getting specific data from a text file in c++

Im doing a login/registration system and the thing Im struggling with is checking whether the password is correct. So I have a text file with the user data that looks like this.
email: email#email.com
username: user123
password: 1234
In order to check if the password given by the user is correct I need to compare it to the one in the file. So how do I extract the password from the *.txt file. I really have no idea where to start.
You could take a look at this answer I found:
Reading file line by line
I think this can be a good start!
Then you can try to keep just the password: Get substring after specific character
Reading a configuration file like that is something useful that you will quickly benefit from. Usually it is a pretty standard code where you iterate through all the lines of your file, reading key-value pairs and storing them (for example, in a std::map<std::string, std::string>), to use them later.
Here you have a commented example of how such code would be:
#include <fstream> // ifstream
#include <sstream> // stringstream
#include <iostream> // cout, endl
#include <iomanip> // ws
#include <map> // map
using namespace std;
int main(){
map<string, string> configuration;
ifstream fin("your_file.txt");
string line;
while(getline(fin, line)){ // loop through every line in the file
string key;
string value;
stringstream ss(line); // make a stream from the line
getline(ss, key, ':'); // read key until :
ss >> ws; // ignore whitespaces
getline(ss, value); // read value until newline
// Store them
configuration[key] = value;
}
cout << "PW: " << configuration["password"] << endl;
return 0;
}
If the words "email" "username" and "password" are written in the text document, start by removing them so it looks like this.
email#email.com
user123
1234
Then if you put the text file in the same folder as the source, this basic program should be a start.
#include <iostream>
#include <fstream>
#include <string>
using std::cout;
using std::cin;
using std::ifstream;
using std::getline;
using std::endl;
using std::string;
int main()
{
ifstream input("info.txt"); //open the text document
string line;
//int lineCounter;
string mail;
string password;
string username;
cout << "Enter your mail: " << endl;
cin >> mail;
cout << "Enter your password: " << endl;
cin >> password;
int compareResult;
if (input.is_open())
{
while(getline (input,line)) //loop through input file line by line
{
if (line.length() > 0) //skip empty lines
{
//lineCounter++; //keeps track of what line you're at
compareResult = line.compare(mail); //compare each line of the document with the entered mail
if (compareResult == 0) //if match..
{
getline (input,line); //get next line (username)
username = line; //store username in a variable
getline (input,line); //get next line (password)
compareResult = line.compare(password); //compare password with entered password
if (compareResult == 0) //if match..
{
cout << "Logged in as " << username << endl;
}
}
}
}
input.close();
}
return 0;
}
Just change the code to match the name of your textfile or vice versa, just tried it and got logged in as user123.
Next time you need to find the answer to something similar, search for something like "searching text file for a particular string c++"
I haven't done anything in c++ in ages, but this question was the first I saw after signing up so I felt compelled,
THANK YOU!

Finding certain characters in a line of string

I want to be able to a string that contains certain characters in a file that contains one string per line.
#include <iostream>
#include <fstream>
#include <string>
int main(){
string line;
ifstream infile;
infile.open("words.txt");
while(getline(infile, line,' ')){
if(line.find('z')){
cout << line;
}
}
}
That's my attempt at finding all the string that contains the character z.
The text file contains random strings such as
fhwaofhz
cbnooeht
rhowhrj
perwqreh
dsladsap
zpuaszu
so with my implementation, it should only print out the strings with the character z in it. However, it seems to be reprinting out all the contents from the text file again.
Problem:
In your file the strings aren't separated by a space (' ') which is the end delimiter, they are separated by a end of line ('\n'), that is a different character. As a consequence, in the first getline everything goes to line. line contains all the text in the file, including z's, so all the content is printed. Finally, the code exits the while block after running once because getline reaches the end of the file and fails.
If you run this code
#include <iostream>
#include <fstream>
#include <string>
int main(){
std::string line;
std::ifstream infile;
infile.open("words.txt");
while(getline(infile, line,' ')){
std::cout << "Hi";
if(line.find('z')){
std::cout << line;
}
}
}
"Hi" will be only printed once. That is because the while block is only executed once.
Additionaly, see that line.find('z') won't return 0 if not match is found, it will return npos. See it running this code (As it says here):
#include <iostream>
#include <fstream>
#include <string>
int main(){
std::string line;
std::ifstream infile;
infile.open("words.txt");
while(getline(infile,line)){
std::cout << line.find('z');
if(line.find('z')){
std::cout << line << "\n";
}
}
}
Solution:
Use getline(infile,line) that is more suitable for this case and replace if(line.find('z')) with if(line.find('z') != line.npos).
while(getline(infile,line)){
if(line.find('z') != line.npos){
std::cout << line << "\n";
}
}
If you need to put more than one string per line you can use the operator >> of ifstream.
Additional information:
Note that the code you posted won't compile because string, cout and ifstream are in the namespace std. Probably it was a part of a longer file where you were using using namespace std;. If that is the case, consider that it is a bad practice (More info here).
Full code:
#include <iostream>
#include <fstream>
#include <string>
int main(){
std::string line;
std::ifstream infile;
infile.open("words.txt");
while(getline(infile,line)){
if(line.find('z') != line.npos){
std::cout << line << "\n";
}
}
}
getline extracts characters from the source and stores them into the variable line until the delimitation character is found. Your delimiter character is a space (" "), which isn't present in the file, so line will contain the whole file.
Try getline(infile, line, '\n') or simply getline(infile, line) instead.
The method find returns the index of the found character, where 0 is a perfectly valid index. If the character is not found, it returns npos. This is a special value whcih indicates "not found", and it's nonzero to allow 0 to refer to a valid index. So the correct check is:
if (line.find('z') != string::npos)
{
// found
}

Problem reading a tab delimited file in C++

Right now I am trying to read in a list of books that have tab separated information and just printing the title. Eventually I will add each piece of info to a vector with their names. When I switched the delimiter to a tab from nothing or a one character space, suddenly nothing was outputted.I've look over stack exchange, but most of these solutions aren't telling me why mine doesn't work.
Here is my code
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
using namespace std;
int main() {
ifstream DataFile;
string str;
string title;
string author;
string publisher;
string date;
string ficornon;
if(!DataFile)
{
cout<<"error";
}
DataFile.open("/Users/Kibitz/Desktop/bestsellers.txt",ios::in);
getline(DataFile,title);
while(!DataFile.eof()) // To get you all the lines.
{
cout<<title<<endl;
getline(DataFile,author);
getline(DataFile,publisher);
getline(DataFile,date);
getline(DataFile,ficornon);
getline(DataFile,title);
}
DataFile.close();
return 0;
}
First two lines of input file:
1876 Gore Vidal Random House 4/11/1976 Fiction
23337 Stephen King Scribner 11/27/2011 Fiction
There is a piece of code that reads your file example correctly and print out to stdout. Please notice delimiters used in 'getline' funcion: tab (character '\t') is used to mark end of data fields, and new line character '\n' is used to mark end of line. Check your data file to see it really contains tab delimiters.
The 'peek' function checks for next character in stream, and if there is not more chars, it sets 'eof' flag of the stream. Because there could be more conditions that can invalidate stream for reading I use good() function as the condition in 'while' loop.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
int main() {
std::ifstream DataFile;
string str;
string title;
string author;
string publisher;
string date;
string ficornon;
DataFile.open("bestsellers.txt",std::ifstream::in);
// getline(DataFile,title); // don't need this line
DataFile.peek(); // try state of stream
while(DataFile.good())
{
getline(DataFile,str, '\t'); // you should specify tab as delimiter between filelds
getline(DataFile,author, '\t'); // IMO, better idea is to use visible character as a delimiter, e.g ',' or ';'
getline(DataFile,publisher, '\t');
getline(DataFile,date,'\t');
getline(DataFile,ficornon,'\n'); // end of line is specified by '\n'
std::cout << str << " " << author << " " << publisher << " " << date << " " << ficornon << std::endl;
DataFile.peek(); // set eof flag if end of data is reached
}
DataFile.close();
return 0;
}
/*
Output:
1876 Gore Vidal Random House 4/11/1976 Fiction
23337 Stephen King Scribner 11/27/2011 Fiction
(Compiled and executed on Ubuntu 18.04 LTS)
*/

c++ found an example on splitting strings trying to figure out why change to it changes result

I'm learning about splitting strings for a program in class, and i came across this example.
#include <string>
#include <sstream>
#include <iostream>
int main()
{
std::string str = "23454323 ABCD EFGH";
std::istringstream iss(str);
std::string word;
while(iss >> word)
{
std::cout << word << '\n';
}
}
I modified so that the user instead inputs the string,but if I input the string stored in str i get 23454323 and not the other material in the string.
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
string str;
cout<<"Enter a postfix with a space between each object:";
cin>>str;
istringstream iss(str);
string word;
while(iss >> word)
{
cout << word << '\n';
}
}
Ok, thanks for the help everyone got it!
You need to modify your input code a little for this to work. Use:
getline(cin, str);
instead of:
cin >> str;
The latter will stop reading a string on whitespace characters.
Because you use the same input operator as for istringstream when you input from cin and it always breaks on whitespace.
That means you only read a single word from the user. You want to use std::getline.
Just as iss >> word reads a single space-separated word from iss, so cin >> str just reads the first word from cin.
To read a whole line, use getline(cin, str).
(Also, get out of the habit of dumping namespace std into the global namespace. It will cause problems as your programs grow.)

How to read the string into a file C++

i have a little problem on writing the string into a file,
How can i write the string into the file and able to view it as ascii text?
because i am able to do that when i set the default value for str but not when i enter a str data
Thanks.
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
fstream out("G://Test.txt");
if(!out) {
cout << "Cannot open output file.\n";
return 1;
}
char str[200];
cout << "Enter Customers data seperate by tab\n";
cin >> str;
cin.ignore();
out.write(str, strlen(str));
out.seekp(0 ,ios::end);
out.close();
return 0;
}
Please use std::string:
#include <string>
std::string str;
std::getline(cin, str);
cout << str;
I'm not sure what the exact problem in your case was, but >> only reads up to the first separator (which is whitespace); getline will read the entire line.
Just note that >> operator will read 1 word.
std::string word;
std::cin >> word; // reads one space seporated word.
// Ignores any initial space. Then read
// into 'word' all character upto (but not including)
// the first space character (the space is gone.
// Note. Space => White Space (' ', '\t', '\v' etc...)
You're working at the wrong level of abstraction. Also, there is no need to seekp to the end of the file before closing the file.
You want to read a string and write a string. As Pavel Minaev has said, this is directly supported via std::string and std::fstream:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ofstream out("G:\\Test.txt");
if(!out) {
std::cout << "Cannot open output file.\n";
return 1;
}
std::cout << "Enter Customer's data seperated by tab\n";
std::string buffer;
std::getline(std::cin, buffer);
out << buffer;
return 0;
}
If you want to write C, use C. Otherwise, take advantage of the language you're using.
I can't believe no one found the problem. The problem was that you were using strlen on a string that wasn't terminated with a null character. strlen will keep iterating until it finds a zero-byte, and an incorrect string length might be returned (or the program might crash - it's Undefined Behavior, who knows?).
The answer is to zero-initialize your string:
char str[200] = {0};
Supplying your own string as the value of str works because those in-memory strings are null-terminated.