I have a file that have multiple lines of the sample data given in the code. Each line is an object. I've been trying to work with string tokenizer but I keep getting errors.
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string>
int main()
{
std::string input = "kevin hill;8;8;jacky knight;5;6;alejandro wilson;jordan walls;6;layla penn;7;mindy kaling;9;jon adams;8;";
std::istringstream ss(input);
std::string token;
std::string mN, fN, mgr, psy, physio, tCo, fCo;
int mSta, mStr, fSta, fStr, psyS, physioS, tCoS, fCoS;
struct points
{
std::string athName, sportName;
int totPoints, sc;
points(int totPoints, int sc, std::string athName, std::string sportName)
{
this->totPoints = totPoints;
this->sc = sc;
this->athName = athName;
this->sportName = sportName;
}
};
while (getline(ss, token, ';'))
{
mN >> mSta >> mStr >> fN >> fSta >> fStr >> mgr >> psy >> psyS >> physio >> physioS >> tCo >> tCoS >> fCo >> fCoS;
}
points *one = new points(mSta, mStr, mN, fN);
std::cout << one->athName << std::endl;
}
I'm getting error in the beginning of the while loop as the >> after mN is giving "no operator matches these operands" error. When I start the while loop with the istringstream ss as:
ss >> mN >> mSta >> .....
It executes, but skips the first name and reads 8;8;jacky as one string and I guess that is because it is trying to complete a string but even then it is skipping the delimiter as it stops reading at a whitespace.
I'm clueless what is happening here. How do I read different data types using delimiters and make objects with them? Any suggestions?
Related
This is my sample text file
enter image description here
1 Class Physics American 3.6 5 Maria Garcia 1-541-754-3010
2 Class Chemical Australian 3.5 4 Maria Hernandez 1-541-754-3233
And I have a group of array and variable.
typedef struct
{
double current;
unsigned int subject;
}CGPA;
typedef struct
{
char program[40];
char state[50];
char name[50];
char contact[50];
string studentid;
CGPA a;
}INFOR;
How can I store them in different variable for later processing use?
Here are the some part of my code but it cannot get the correct value and store them to my struct array from my txt file:
for( int i = 0; getline(readfile, line); i++)
{
//getline(readfile,student[i].id, '\0');
//getline(readfile,student[i].a.subject, '\0');
//strcpy(student[i].subject, temporary_s);
readfile >> student[i].studentid >> student[i].program >> student[i].state >> student[i].a.current >> student[i].a.subject >> student[i].name >> student[i].contact; //This is my code cannot read my text file correctly
++line_count;
}
This is my sample output:
enter image description here
I want to delete certain line, update certain line of my file and show up the lower or higher CGPA, this is why i need to restore my text file value to the array for later processing use.
This code cannot read my file in right way, I don't know to to deal with it
readfile >> student[i].studentid >> student[i].program >> student[i].state >> student[i].a.current >>student[i].a.subject >> student[i].name >> student[i].contact; //This is my code cannot read my text file correct
I don't know why you need a separate struct for the CGPA data when you could put it into INFOR with the rest but I have left it. I did change all the character arrays to std::string since there was no obvious advantage to them being character arrays. And I changed the array of INFOR to a std::vector since there was no obvious advantage to it being an array. If the structs really do need to be laid out as you had them let me know because the code will need to be changed.
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
struct CGPA
{
double current;
unsigned int subject;
};
struct INFOR
{
std::string program;
std::string state;
std::string name;
std::string contact;
std::string studentid;
CGPA a;
};
bool testing = true;
main() {
if(testing) {
std::ofstream writeFile("file.txt");
writeFile << "1\tClass Physics\tAmerican\t3.6\t5\tMaria Garcia\t1-541-754-3010\n"
<< "2\tClass Chemical\tAustralian\t3.5\t4\tMaria Hernandez\t1-541-754-3233\n";
writeFile.close();
}
std::vector<INFOR> students;
std::ifstream readfile("file.txt");
std::string line;
while(std::getline(readfile, line))
{
std::stringstream ss(line);
INFOR student;
std::string column;
getline(ss, column, '\t'); student.studentid = column;
getline(ss, column, '\t'); student.program = column;
getline(ss, column, '\t'); student.state = column;
ss >> student.a.current;
ss >> student.a.subject;
getline(ss, column, '\t'); student.name = column;
getline(ss, column, '\t'); student.contact = column;
students.push_back(student);
}
readfile.close();
int line_count = students.size();
if(testing) {
std::cout << line_count << " lines";
}
return line_count;
}
I'm currently trying to load a text file into struct data members. Each number is separated by a comma.
#include<string>
#include<sstream>
using namespace std;
struct server{
bool isBusy;
};
struct pass{
double arrivalTime = 0;
double serviceTime = 0;
int classType = 0;
};
int main(){
string fileName;
string line;
pass Pass;
cout << "Enter file name: ";
cin >> fileName;
ifstream fin(fileName);
while (getline(fin, line, ','))
{
/*NEED HELP HERE*/
fin >> Pass[0].arrivalTime;
fin >> Pass[0].serviceTime;
fin >> Pass[0].classType;
}
}
Here is an example of the text file.
0.951412936,2.131445423,0
1.902743503,2.010703852,0
2.537819984,2.326199911,0
3.425838997,1.603712153,0
3.502553324,0.998192867,0
3.917348666,1.49223429,0
4.391605986,0.831661367,0
4.947059678,0.8557003,0
5.429305232,2.42029408,0
The data in the text file follows this format:
arrivalTime,serviceTime,classType
As you can see i have split the line up and stored it in "line" using the comma delimiter, but i am unsure how to load each number into the struct in the while loop.
Any help would be appreciated.
Define an istream operator >> for your struct. Something like
struct pass {
double arrivalTime = 0;
double serviceTime = 0;
int classType = 0;
friend std::istream & operator >>(std::istream & in, pass & p) {
char c;
in >> p.arrivalTime >> c >> p.serviceTime >> c >> p.classType;
return in;
}
};
Then, simply
pass Pass;
fin >> Pass;
while (getline(fin, line))
{
sscanf(line.c_str(), "%lf,%lf,%d", &arrivalTime, &serviceTime, &classType);
}
This loop is wrong:
while (getline(fin, line, ','))
{
/*NEED HELP HERE*/
fin >> Pass[0].arrivalTime;
fin >> Pass[0].serviceTime;
fin >> Pass[0].classType;
}
You are reading everything from the stream up to the next ',' character, then trying to read more from the stream.
Given the input file:
0.951412936,2.131445423,0
1.902743503,2.010703852,0
2.537819984,2.326199911,0
Your program reads "0.951412936" into line (and discards the ',') then tries to read the next input into Pass[0].arrivalTime but the next input is 2.131445423, which was meant to be the serviceTime (which you already read into line).
As Shreevardhan suggests you can define an operator for reading your struct from a stream. I would make it more reliable like so:
struct ExpectedChar { char expected; };
// read a character from a stream and check it has the expected value
std::istream& operator>>(std::istream& in, const ExpectedChar& e)
{
char c;
if (in >> c)
if (c != e.expected) // failed to read expected character
in.setstate(std::ios::failbit);
return in;
}
// read a struct pass from a stream
std::istream& operator>>(std::istream& in, pass& p)
{
ExpectedChar comma{ ',' };
in >> p.arrivalTime >> comma >> p.serviceTime >> comma >> p.classType;
return in;
}
This will stop reading if the input file does not meet the expected format. Now you can do:
while (fin >> Pass)
{
// do something with each pass
}
if (!fin.eof()) // stopped reading before end-of-file
throw std::runtime_error("Invalid data in input file");
This will keep reading a pass from the file until reading fails, either because it reached the end of the file, or because there was some bad data in the file. If there is bad data it throws an exception.
#include<string>
#include<iostream>
#include<fstream>
#include<vector>
using namespace std;
struct server{
bool isBusy;
};
struct pass{
double arrivalTime;
double serviceTime;
int classType;
friend std::istream & operator >>(std::istream &in, pass &p) {
char c;
in >> p.arrivalTime >> c >> p.serviceTime >> c >> p.classType;
return in;
}
};
int main(){
string fileName;
string line;
cout << "Enter file name: ";
cin >> fileName;
ifstream fin(fileName.c_str(), ifstream::in);
vector<pass> passes;
pass Pass;
while (fin>>Pass)
passes.push_back(Pass);
for(vector<pass>::const_iterator iter = passes.begin();
iter != passes.end();
++iter)
std::cout<<iter->arrivalTime<<" "<<iter->serviceTime<<" "
<<iter->classType<<std::endl;
}
Here is hint;
string line;
string temp;
string::size_type sz;
while (getline(cin, line))
{
istringstream ss( line );
getline( ss, temp, ',' );
double arrivalTime = stod(temp, &sz);
getline( ss, temp, ',' );
double serviceTime = stod(temp, &sz);
getline( ss, temp, ',' );
double classType = stod(temp, &sz);
cout << arrivalTime << ' '
<< serviceTime << ' '
<< classType << endl;
}
[EDIT]
I specified my question, maybe it has more information:
I have a file with lots of lines like "string1 string2 int1 int2", so a line contains two strings and two integers. I would like to read the file line by line and push those four datas into a vector of my struct( which has the same variable types and num ). My question is, how can I do this, because the >> operator won't work anyway. Nor the getline().
and the code:
void FromFile(string filename)
{
ifstream stream;
stream.open(filename);
adatok adattemp;
while(stream.good())
{
stream >> adattemp.agresszor >> adattemp.vedo >> adattemp.haborukezdete >> adattemp.haboruvege >> ws;
cout << adattemp.agresszor;
vektor.push_back(adattemp);
}
stream.close();
}
Assuming each string is just a single word, this should work:
#include <vector>
#include <string>
#include <fstream>
struct Entry {
std::string s1;
std::string s2;
int i1;
int i2;
};
std::vector<Entry> entries;
int main()
{
std::ifstream file("yourfile");
while (file.good()) {
Entry entry;
file >> entry.s1 >> entry.s2 >> entry.i1 >> entry.i2 >> std::ws;
entries.push_back(entry);
}
return 0;
}
Note: it's important to include >> std::ws at the end of reading each line. It eats up extra whitespace. Otherwise you'll end up with an extra junk entry at the end of the file.
EDIT: As Simple pointed out in the comments, if any errors occur while reading the file, the above code will store a junk entry at the end of the vector. This code will fix that by making sure there are no errors before storing the entry:
Entry entry;
while (file >> entry.s1 >> entry.s2 >> entry.i1 >> entry.i2 >> std::ws)
{
entries.push_back(entry);
}
I'd overload >> and use std::copy
#include<vector>
#include<algorithm>
//...
struct Reader {
std::string str1;
std::string str2;
int int1;
int int2;
friend std::istream& operator << (std::istream& is, Reader &r)
{
return is >> r.str1 >> r.st2 >> r.int1 >> r.int2 ;
}
};
std::vector<Reader> vec;
std::ifstream fin("file_name");
std::copy(std::istream_iterator<Reader>(fin),
std::istream_iterator<Reader>(),
std::back_inserter(vec)
) ;
This assumes all string and int are seperated by white space
You can also overload >> too to display content in similar fashion
Since you do not know the file size, a vector would be more suited IMO.
while ( myFile >> string1 >> string2 >> myInt1 >> myInt2 ) {
stringvec1.push_back( string1 );
stringvec2.push_back( string2 );
intvec1.push_back( myInt1 );
intvec2.push_back( myInt2 );
}
EDIT:
If the 4 variables that you are reading correspond to a particular logically meaningful class, then you can have one vector of class/struct with all these 4 as members.
Something like:
struct myFileVariables {
std:string m_string1;
std:string m_string2;
int m_myInt1;
int m_myInt2;
myFileVariables ( string string1, string string2, int myInt1, int myInt2 ) :
m_string1( string1 ), m_string2( string2 ), m_myInt1( myInt1 ),
m_myInt2( myInt2 ) {}
};
And in your main function:
while ( myFile >> string1 >> string2 >> myInt1 >> myInt2 ) {
myFileVariables newEntry( string1, string2, myInt1, myInt2 );
myVec.push_back( newEntry );
}
#include <iostream>
#include <fstream>
#include <string>
#include <cctype> // isdigit();
using namespace std;
int main()
{
ifstream fin;
fin.open("Sayı.txt");
while (!fin.eof()){
string word;
int n;
fin >> word; //First i read it as a string.
if (isdigit(word[0])){ //checks whether is it an int or not
fin.unget(); //
fin >> n; // if its a int read it as an int
cout << n << endl;
}
}
}
Suppose the text file is something like this:
100200300 Glass
Oven 400500601
My aim is simply to read integers from that text file and show them in console.
So the output should be like
100200300
400500601
You can see my attempt above.As output i get only the last digit of integers.Here's a sample output:
0
1
Simple just try converting the string read to an int using string streams, if it fails then it isn't an integer , otherwise it is an integer.
ifstream fin;
istringstream iss;
fin.open("Say1.txt");
string word;
while (fin>>word )
{
int n=NULL;
iss.str(word);
iss>>n;
if (!iss.fail())
cout<<n<<endl;
iss.clear();
}
I think the following should do what you want (untested code):
int c;
while ((fin >> std::ws, c = fin.peek()) != EOF)
{
if (is_digit(c))
{
int n;
fin >> n;
std::cout << n << std::endl;
}
else
{
std::string s;
fin >> s;
}
}
This is my problem: I read some lines from a txt. This txt is like this:
Ciao: 2000
Kulo: 5000
Aereo: 7000
ecc. I have to assign every word before(':') to a string and then to a map; and the numbers to a int and then to a map. The problem is that beginning from the second line, my string become ("\nKulo") ecc! I don't want this! What can I do?
This is the code:
#include <iostream>
#include <fstream>
#include <string>
#include <map>
using namespace std;
int main()
{
map <string, int> record;
string nome, input;
int valore;
ifstream file("punteggi.txt");
while (file.good()) {
getline(file, nome, ':');
// nome.erase(0,2); //Elimina lo spazio iniziale
file >> valore;
record[nome] = valore;
cout << nome;
}
file.close();
cout << "\nNome: ";
cin >> input;
cout << input << ": " << record[input] << "\n";
cout << "\n\n";
return 0;
}
The issue you have is that std::getline() is an unformatted input function and as such doesn't skip leading whitespace. From the looks of it, you want to skip leading whitespace:
while (std::getline(in >> std::ws, nome, ':') >> valore) {
...
}
Alternatively, if there are leading spaces, you can ignore() all characters up to the end of line after reading a value.
BTW, since I saw someone over here recommending the use of std::endl: do not use std::endl unless you really intend to flush the buffer. It is a frequent major performance problem when writing files.
Use the standard line reading idiom:
for (std::string line; std::getline(file, line); )
{
std::string key;
int n;
std::istringstream iss(line);
if (!(iss >> key >> n) || key.back() != ':') { /* format error */ }
m.insert(std::make_pair(std::string(key.cbegin(), std::prev(key.cend()),
n));
}
(Instead of the temporary string-from-iterators, you can also use key.substr(0, key.length() - 1), although I imagine that my version may be a bit more efficient. Or add a key.pop_back(); before inserting the data into the map.)