This is a code for reading in .txt file and spliting it by : and printing out the result. But I got stuck on the while-loop. This is my code.
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
using namespace std;
string* split(const string& str, const string& delim) {
string* string_list = new string[10];
int idx = 0;
char *token = strtok(const_cast<char*>(str.c_str()), delim.c_str());
while (token != NULL) {
string_list[idx] = token;
token = strtok(NULL, delim.c_str());
++idx;
}
return string_list;
}
struct Item {
string name;
string age;
string id;
string subject[10];
};
struct Item* create_item() {
struct Item* pitem = new Item;
return pitem;
};
void insert_item(struct Item *prev_item, struct Item *item) {
item = (prev_item + 5);
}
int main() {
string student, student2;
string *string_list, *subject, *string_list2, *subject2;
struct Item* pstudent, *pstudent2;
ifstream fin;
fin.open("input.txt");
fin >> student;
while (student != "\n") {
string_list = split(student, ":");
pstudent = create_item();
pstudent->name = *string_list;
pstudent->age = *(string_list + 1);
pstudent->id = *(string_list + 2);
subject = split(*(string_list + 3), ",");
for (int i = 0; i < 10; i++) {
if (*(subject + i) != "") {
pstudent->subject[i] = *(subject + i);
}
}
cout << *(string_list+1) << endl;
fin >> student2;
string_list = split(student2, ":");
pstudent2 = create_item();
insert_item(pstudent, pstudent2);
pstudent2->name = *(string_list);
pstudent2->age = *(string_list + 1);
pstudent2->id = *(string_list + 2);
subject2 = split(*(string_list + 3), ",");
for (int i = 0; i < 10; i++) {
if (*(subject2 + i) != "") {
pstudent2->subject[i] = *(subject2 + i);
}
}
}
cout << pstudent2->name << endl;
fin.close();
return 0;
}
I am still working on this code, but the while-loop in the main() will not stop. I wanted it to stop when the input.txt file input is a new line.
input.txt is
Mary:20:287:Math,Algorithm\n
Tom:21:202:Math,English\n
Hee:20:256:Math
thanks in advance!
Don't try to process more than one student in the body of the loop.
Rather than trying to write a linked-list type, use an existing collection type.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using strings_view = std::vector<std::string_view>;
strings_view split(std::string_view str, char delim) {
strings_view view;
while (str.size())
{
auto pos = str.find(delim);
view.push_back(str.substr(0, pos - 1));
str = str.substr(pos + 1);
}
return view;
}
struct Item {
std::string name;
std::string age;
std::string id;
std::vector<std::string> subject;
};
int main() {
std::vector<Item> students;
std::ifstream fin("input.txt");
for (std::string line; get_line(fin, line);) {
strings_view view = split(line, ':');
Item student;
student.name = view[0];
student.age = view[1];
student.id = view[2];
string_view subject = split(view[3], ',')
student.subject.assign(subject.begin(), subject.end());
students.push_back(student);
}
std::cout << students[1].name << std::endl;
return 0;
}
Related
In the below program i have inputted multiple string inputs like in the example below. Now i want to assign the multiple lines parsed data into different variables of different type.
int main()
{
int line=3, t;
string s, bigString;
for(int i=0 ; i<line ; i++)
{
getline(cin,s);
bigString += s + "\n";
}
cout <<bigString <<endl;
return 0;
}
Sample Input:
1 toy at 10.65
2 box of books at 12.11
1 pot plant at 6.45
I would like to parse and assign my variables like below,
//For storing array of variables,
int quantity;
Map<string,double>itemAndPrice;
ex1:
quantity = 1
itemAndPrice.first() = toy;
itemAndPrice.second() = 10.65;
ex2:
quantity = 2
itemAndPrice.first() = box of
books;
itemAndPrice.second() = 12.11;
ex3:
quantity = 1
itemAndPrice.first() = pot plant;
itemAndPrice.second() = 6.45;
As every input is different, how to parse and assign in respective variables in a generic way.
Why are you concatenating all of the inputs into a single string? And why are you using a Map for holding single items? I would suggest defining a struct to hold the different fields you need, and then have your reading loop parse the individual lines into a vector holding that struct type, eg:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
struct itemInfo
{
int quantity;
std::string name;
double price;
};
int main()
{
std::string line;
std::vector<itemInfo> items;
while (std::getline(std::cin, line))
{
try
{
itemInfo item;
auto start = line.find_first_not_of(" \t");
auto stop = line.find_first_of(" \t", start + 1);
item.quantity = std::stoi(line.substr(start, stop - start));
start = line.find_first_not_of(" \t", stop + 1);
stop = line.find(" at ", start);
item.name = line.substr(start, stop - start);
start = line.find_first_not_of(" \t", stop + 4);
item.price = std::stod(line.substr(start));
items.push_back(item);
}
catch (const std::logic_error &) { }
}
// use items as needed...
return 0;
}
Online Demo
You could then take this a step further by moving the parsing logic into an overloaded operator>> for the struct, eg:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
struct itemInfo
{
int quantity;
std::string name;
double price;
};
std::istream& operator>>(std::istream &in, itemInfo &item)
{
try
{
std::string line;
if (std::getline(in, line))
{
auto start = line.find_first_not_of(" \t");
auto stop = line.find_first_of(" \t", start + 1);
item.quantity = std::stoi(line.substr(start, stop - start));
start = line.find_first_not_of(" \t", stop + 1);
stop = line.find(" at ", start);
item.name = line.substr(start, stop - start);
start = line.find_first_not_of(" \t", stop + 4);
item.price = std::stod(line.substr(start));
}
}
catch (const std::logic_error &)
{
in.setstate(std::ios_base::failbit);
}
return in;
}
int main()
{
itemInfo item;
std::vector<itemInfo> items;
while (std::cin >> item)
{
items.push_back(item);
}
// use items as needed...
return 0;
}
Online Demo
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.
CString s;
int res = 0;
char *existing;
char *current;
existing = strtok(urls, ",");
current = strtok(storedurls, ",");
while (existing != NULL)
{
while (current != NULL)
{
res = strcmp(existing, current);
if (res == 0) continue;
s.Append(current);
current = strtok(NULL, ",");
if (current != NULL) s.Append(",");
}
existing = strtok(NULL, ",");
}
strcat(urls, s);
We have a string of storedurl L("url1,url2,url3") and urls L("url3,url5") and I want to store the unique urls from both string and get a single output as L("url1,url2,url3,url5")
Stop using C-style string functions in C++ and get acquainted with the C++ Standard Library.
#include <algorithm>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
std::vector<std::string> split(std::string const& src, char delim = ',')
{
std::vector<std::string> dst;
std::stringstream ss{ src };
std::string tmp;
while (std::getline(ss, tmp, delim))
dst.push_back(tmp);
return dst;
}
int main()
{
std::string foo{ "url1,url2,url4" };
std::string bar{ "url2,url3,url5" };
auto foo_urls{ split(foo) };
auto bar_urls{ split(bar) };
std::vector<std::string> unique_urls{ foo_urls.begin(), foo_urls.end() };
unique_urls.reserve(foo_urls.size() + bar_urls.size());
unique_urls.insert(unique_urls.end(), bar_urls.begin(), bar_urls.end());
std::sort(unique_urls.begin(), unique_urls.end());
unique_urls.erase(std::unique(unique_urls.begin(), unique_urls.end()), unique_urls.end());
for (auto const& url : unique_urls)
std::cout << url << '\n';
}
DWORD res = 0;
CString existingUrls = urls;
CString curUrls;
CString curItemInExitingUrl;
CString curItemInCurUrl;
CString urlsToAdd;
while (!existingUrls.IsEmpty()) {
CWinLogFile::GetTok(existingUrls, _T(","), curItemInExitingUrl);
curUrls = src.urls;
while (!curUrls.IsEmpty()) {
CWinLogFile::GetTok(curUrls, _T(","), curItemInCurUrl);
if (curItemInExitingUrl.Compare(curItemInCurUrl)==0)
{
res = 1;
}
}
if (res == 0)
{
urlsToAdd.Append(curItemInExitingUrl);
urlsToAdd.AppendChar(',');
}
else
res = 0;
}
urlsToAdd.Append(src.urls);
Found the solution for my posted question. Where urls & src.urls are two comma separated values of urls. Thanks.
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
Hello i want to cut string in this situation:
if (std::count(text.begin(), text.end(), ',') > 3 {
//Cut String after 3 ','
}
text look like this:
"item1, item2, item3, item4, item5"
and i want this:
"item1, item2, item3, item4[Cut everything out on the right side >>], item5"
and return
"item1, item2, item3, item4"
Looking on first answer im looking for something like this(but working):
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
string s1 = "item1, item2, item3, item4, item5";
if(std::count(s1.begin(), s1.end(), ',') > 3) {
int comma = 0;
int x = sizeof(s1);
for(int i = 0; i < x; i++) {
if (comma == 3) {
string sub = s1.substr(0, i);
cout << "String is: " << sub;
}
if(s1[i] == ',') {
comma++;
}
}
}
return 0;
}
Look at std::string::substr
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
// Take any string
string s1 = "item1, item2, item3, item4, item5";
// Start at position 0 to position of character ',' in "item4,"
string sub = s1.substr(0, 26);
// prints item1, item2, item3, item4
cout << "String is: " << sub;
return 0;
}
You need to change little code as below.
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
string s1 = "item1, item2, item3, item4, item5";
int comma = 0;
int x = s1.length();
bool flag = false;
for(int i = 0; i < x; i++) {
if (comma == 4) {
string sub = s1.substr(0, i-1);
cout << "String is: " << sub;
flag = false;
return 0;
}
if(s1[i] == ',') {
comma++;
}
else{
flag = true;
}
}
if(flag)
cout<<"String not contain more then 3 comma's \n String is :: "<<s1;
return 0;
}
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
string s1 = "item1, item2, item3, item4, item5";
if(std::count(s1.begin(), s1.end(), ',') > 3) {
int comma = 0;
int x = s1.length();
for(int i = 0; i < x; i++) {
if (comma == 3) {
string sub = s1.substr(0, i-1);
cout << "String is: " << sub;
return sub;
}
if(s1[i] == ',') {
comma++;
}
}
}
return 0;
}
There is no need to use std::count(), that is just wasted overhead. You are scanning the string twice when once would suffice.
Also, your use of sizeof() is wrong, you need to use std::string::size() instead. sizeof(s1) tells you the byte size of s1 (ie, of the std::string class itself) at compile-time, whereas s1.size() tells you how many characters are in s1 at runtime.
I suggest using std::string::find() in a loop, eg:
#include <string>
#include <iostream>
std::string cutAtNComma(const std::string &s, int n) {
std::string::size_type idx = 0;
while (n-- > 0) {
idx = s.find(',', idx);
if (idx == std::string::npos) break;
if (n == 0) return s.substr(0, idx);
++idx;
}
return s;
}
int main() {
std::string s1 = "item1, item2, item3, item4, item5";
std::string sub = cutAtNComma(s1, 4);
std::cout << "String is: " << sub;
return 0;
}
Live Demo
Alternatively, you can use std::find_if() instead, eg:
#include <string>
#include <iostream>
#include <algorithm>
std::string cutAtNComma(const std::string &s, int n) {
auto iter = std::find_if(s.cbegin(), s.cend(),
[n](char c) mutable {
if (c == ',') {
if (--n == 0) return true;
}
return false;
}
);
if (iter != s.cend()) return std::string(s.cbegin(), iter);
return s;
}
int main() {
std::string s1 = "item1, item2, item3, item4, item5";
std::string sub = cutAtNComma(s1, 4);
std::cout << "String is: " << sub;
return 0;
}
Live Demo