I am reading File that contains
Boss, level, Specials,
"FireMen", 3, "Flame,Thrower", Fire,Breath
"Medusa", 6, "Snake,Poison"
"Hype", 10, "One,punch,Knock", Fly,Kick, "Dragon,Breath"
I am trying to read it into class with objects boss, level and specials
I am having problem reading from file since I split each by words by comma but it read specials like Flame,Thrower as separate due to comma in between them. How can I combine specials rather then splitting by commas so that it read Flame Thrower rather then Flame and thrower separately.
Also some specials are in quotation others are not.
I have been stuck at reading this rather complicated file. If anyone has time to read through my code and fix 10s of errors that I am getting would greatly be appreciated, Thank You
(What I did doesn't make much sense since this is my one month into C++ so still newbie and progressing)
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include "Boss.h"
using namespace std;
vector <Boss*> Info;
Boss* parseLine(string str)
{
vector<string> store;
string smt = " ";
Boss* values = nullptr;
if (smt != "")
{
(store.push_back(smt));
}
for (int i = 0; i < (int)str.size(); i++)
{
char ch = str[i];
if (ch != ',')
{
smt = smt + ch;
}
else
{
store.push_back(smt);
smt = "";
}
}
values = new Boss(store[0], stoi(store[1]), store[2]);
Name = store[0];
Level = store[1];
Specials = store[2];
return values;
}
bool readFile()
{
std::ifstream myFile("Bosses.txt");
if (!myFile.is_open())
{
cout << "fAILED" << "\n";
return false;
}
string str;
int i = 0;
while (std::getline(myFile, str))
{
cout << str << endl;
if (str[0] != '/')
{
Boss* Boss = parseLine(str);
result.push_back(Boss);
}
}
return true;
}
int main()
{
std::cout << "Read file\n;";
bool data = readFile();
for (Boss* t : result)
{
delete t;
}
And Class
#include <string>
#include <vector>
class Boss {
std::string Name;
int Level;
std::vector<std::string> Specials;
Boss(std::string Name, int Level, std::vector<std::string> Specials);
~Boss();
Boss(Boss& b);
void setName(std::string Name);
void setLevel(int Level);
};
Boss::Boss(std::string Name, int Level, std::vector<std::string> Specials)
{
this->Name= Name;
this->Level = Level;
this->Specials = Specials;
}
Boss::~Boss() {}
Boss::Boss(Boss& b)
{
Name = b.Name;
Level = b.Level;
Specials = b.Specials;
}
void Boss::setName(std::string Name) {
this->Name = Name;
}
void Boss::setLevel(int Level)
{
this->Level = Level;
}
This code reads your file and stores the data in the std::vector Info using stringstreams and other things to parse.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include <sstream>
using namespace std;
class Boss {
std::string Name;
int Level;
std::vector<std::string> Specials;
public:
Boss(std::string n, int l, std::vector<std::string> s)
{
this->Name = n;
this->Level = l;
this->Specials = s;
};
~Boss() {};
Boss(const Boss& b) {
this->Name = b.Name;
this->Level = b.Level;
this->Specials = b.Specials;
};
Boss() {};
Boss operator= (Boss b) {
this->Name = b.Name;
this->Level = b.Level;
this->Specials = b.Specials;
return b;
}
void setName(std::string n) { Name = n; };
void setLevel(int l) { Level = l; };
void setSpecials(std::vector<std::string> s) {Specials = s;}
std::string getName() const { return Name; }
int getLevel() const { return Level; }
std::vector<std::string> getSpecials() const { return Specials; }
};
vector <Boss> Info;
Boss parseLine(string str)
{
vector<string> store;
string smt;
stringstream evaluator;
Boss value;
evaluator << str; //put our string into evaluator
{
char double_quote_remover;
evaluator >> double_quote_remover; //remove the first double quote
getline(evaluator, smt, '"'); //get the name until the next double quote
char comma_remover;
evaluator >> comma_remover; //remove the comma
}
value.setName(smt); //put smt into the Boss's name
{
int Level;
evaluator >> Level; //get an int from our string
value.setLevel(Level); //put our int into our Boss
}
char curr;
while (evaluator >> curr && curr != ','); //get the comma after the int
smt = ""; //reset
curr = ' '; //reset
while (evaluator >> curr) { //while we read chars into curr
if (isalpha(curr)) { evaluator.putback(curr); curr = ','; } //if the char is a letter, put it back
if (curr == '\"') getline(evaluator,smt,'\"'); //if the char is a double quote, read until we reach another
else if (curr == ',') getline(evaluator,smt,','); //if the char is a comma, read until we get another
if (smt != "") //if the string is not null, put it in store
store.push_back(smt);
smt = ""; //reset
}
value.setSpecials(store); //put store into our Boss
return value; //return our boss
}
bool readFile()
{
std::ifstream myFile("Bosses.txt");
if (!myFile.is_open())
{
cout << "FAILED" << "\n";
return false;
}
string str;
getline(myFile, str); //for the first line, which we don't need
int i = 0;
while (std::getline(myFile, str))
{
Boss Boss = parseLine(str);
Info.push_back(Boss);
}
return true;
}
int main()
{
bool data = readFile();
}
This should work. I have tested it thouroughly. Inform me of any errors.
Note: There was no need for pointers that were in your original code.
So I am using stringstream in a function in c++ to take the numbers from a string, and then return the numbers to an array in main, but for some reason, they always return as 0 instead of the actual numbers. Code is below, does anyone know how to fix this?
int main()
{
for(int i = 0; i < userInput.length(); i++)
{
...
else
{
chemNumbers[i] = extractIntegerWords(userInput);
cout << chemNumbers[i] << endl;
}
}
int extractIntegerWords(string str)
{
stringstream ss;
int num = 0;
ss << str;
/* Running loop till the end of the stream */
string temp;
int found;
if(!ss.eof())
{
ss >> temp;
if (stringstream(temp) >> found)
{
num = found;
}
temp = "";
}
return found;
}
The original if statement doesn't pertain to the function only what is seen in the else statement, which is in main
This is off the top of my head and I don't have much time to test it, but this should put you in the right direction:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using std::cout;
using std::endl;
using std::istringstream;
using std::string;
using std::vector;
inline bool tryGetInt(const string& str, string& out) { istringstream sStream(str); return !(sStream >> out).fail(); } /*!< Tries to parse a string to int. */
void splitString(const string &str, const string &delimiters, vector<string> &tokens) {
// Skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos) {
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
}
}
int32_t main(int argCount, char* argValues[]) {
for (int32_t i = 0; i < argCount; i++) {
cout << "Found argument " << argValues[i] << endl;
auto foundIntegers = getIntegerFromString(string(argValues[i]));
// Do whatever
}
return 0;
}
vector<int64_t> getIntegerFromString(string formula) {
vector<int64_t> foundInts;
string temp;
if (tryGetInt(formula, temp)) {
vector<string> intsAsStrings;
splitString(temp, " ", intsAsStrings);
for (auto item : intsAsStrings) {
foundInts.push_back(stol(item));
}
}
return foundInts;
}
Regular expression might help:
std::vector<std::pair<std::string, std::size_t>> Extract(const std::string& s)
{
std::vector<std::pair<std::string, std::size_t>> res;
const std::regex reg{R"(([a-zA-Z]+)(\d*))"};
for (auto it = std::sregex_iterator(s.begin(), s.end(), reg);
it != std::sregex_iterator();
++it)
{
auto m = *it;
res.push_back({m[1], m[2].length() == 0 ? 1 : std::stoi(m[2])});
}
return res;
}
int main()
{
for (auto p : Extract("C6H12O6")) {
std::cout << p.first << ": " << p.second << std::endl;
}
}
Demo
I add option for array instead vector for #I'mbadatCS
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
vector<int> extractIntegerWords(const string& _str)
//for array option: void extractIntegerWords(const string& _str, int* numArr)
{
stringstream ss;
ss << _str;
vector<int> vec;
string temp;
int found;
//for array option: int idx = 0;
while(!ss.eof())
{
ss >> temp;
if (stringstream(temp) >> found)
{
vec.push_back(found);
//for array option:numArr[idx++] = found;
}
temp = "";
}
return vec;
//for array option: return;
}
int main()
{
string s = "bla 66 bla 9999 !"
vector<int> res = extractIntegerWords(s);
for (int i = 0; i < res.size(); ++i)
{
cout << res[i] << ", " << endl;
}
}
a few comments:
const string& in input argument, not string. you don't want harm your source data
you need a loop not "if" (like ths the operation will run just one time)
where your array??
in C++ prefer use vector and not array
Well I have that code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
std::string s = "0,0,0,1,1,1,0,0,1";
std::string delimiter = ",";
int x = 0;
std::string mapa[9];
size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
std::cout << token << std::endl;
s.erase(0, pos + delimiter.length());
mapa[x] = token;
x++;
}
std::cout << s << std::endl;
cin.get();
}
Parse (split) a string in C++ using string delimiter (standard C++)
I have x array, but I need a second dimension the Y... I get the content from a text file called map.txt:
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
And I need to split it by commas (for the x) and later by newlines (for y)...
But Idk how to do the Y array... What Can I do?
Thanks!
You may read the lines from the file as
fstream fstr;
fstr.open("file.txt",ios::in);
string str;
int yDimension = 0;
while(getline(fstr,str)
{
yDimension++; //do appropriate thing with the y dimension
std::string token;
while ((pos = str.find(delimiter)) != std::string::npos) {
token = str.substr(0, pos);
std::cout << token << std::endl;
str.erase(0, pos + delimiter.length());
mapa[x] = token;
x++;
}
}
You can read the entire file of any number of rows with any number of comma-delimited columns (memory-permitting) with this:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <vector>
struct int_reader : std::ctype<char>
{
int_reader() : std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
rc[','] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
return &rc[0];
}
};
int main()
{
std::vector<std::vector<int> > myFileData;
std::ifstream fin("MyDataFile.txt", std::ifstream::in);
std::string buffer;
while (std::getline(fin, buffer))
{
std::stringstream ss(buffer);
std::vector<int> t;
int_reader reader;
ss.imbue(std::locale(std::locale(), &reader));
std::copy(std::istream_iterator<int>(ss), std::istream_iterator<int>(), std::back_inserter(t));
myFileData.push_back(t);
}
// do whatever you need to with the loaded arrays ...
return 0;
}
You can use ifstream::getline(), with a delimiter ','
ifstream file ( "map.txt" );
string value;
while ( file.good() )
{
getline ( file, value, ',' );
}
Or you can read all the text and use regular expression to take each text out between delimiter.
The sortest way to do that without vectors:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
fstream fstr;
fstr.open("mapa.txt");
char mapa[31][9];
int x = 0, y = 0;
char c;
while(fstr.good())
{
c = fstr.get();
if (c!= ',') {
mapa[x][y] = c;
x++;
}
if (c=='\n')
{
x = 0;
y++;
}
}
fstr.close();
cin.get();
}
Only 32 lines!! :D