Reputation: 3
I have an issue that I haven't been able to find a good way to solve, mostly because I am relatively new to C++, but not new to programming. I have a file with several lines in it, one of them being:
Plain Egg 1.45
I need to be able to read that line and split the first part, "Plain Egg", into a string, and then the last part, 1.45, into a float, and then do that for the rest of the lines. The following is some code I have so far, but I have been having an issue where it refuses to even read the file for some reason:
string line;
ifstream menuFile("menu.txt");
if (menuFile.is_open())
{
int i = 0;
while (getline(menuFile, line));
{
cout << line << endl;
istringstream iss(line);
iss >> dataList[i].menuItem >> dataList[i].menuPrice;
/*iss >> dataList[i].menuPrice;*/
i++;
}
}
else
{
cout << "Unable to open file.";
}
When I run it, it doesn't spit out "Unable to open file.", and when I trace it, it does enter the if loop, but it just doesn't read it. Besides that problem though, I want to know if this code would work in the way I want it to, and if doesn't, how to solve this problem.
EDIT: When I run it, it outputs what the last line of the file said, that being "Tea 0.75". The full file is as follows:
Plain Egg 1.45
Bacon and Egg 2.45
Muffin 0.99
French Toast 1.99
Fruit Basket 2.49
Cereal 0.69
Coffee 0.50
Tea 0.75
EDIT 2: For some reason, the following code goes straight to the last line, Tea 0.75, and I have no idea why, shouldn't the getline just go line by line until the last line(?):
string line;
int index;
ifstream menuFile("menu.txt");
if (menuFile.is_open())
{
while (getline(menuFile, line));
{
cout << line << endl;
index = line.find_last_of(' ');
cout << index << endl;
}
}
EDIT 3: Above code has a semicolon at the end of the while loop, no wonder it was just ending on the last line, ughhh.
Upvotes: 0
Views: 375
Reputation: 8064
#include <iostream> // cout
#include <string> // find_last_of, getline, stod
int main()
{
std::string line{};
while (std::getline(std::cin, line))
{
auto pos{line.find_last_of(' ')};
auto text{line.substr(0, pos)};
auto number{std::stod(line.substr(pos))};
std::cout << "text = " << text << ", number = " << number << "\n";
}
}
// Outputs
//
// text = Plain Egg, number = 1.45
// text = Bacon and Egg, number = 2.45
// text = Muffin, number = 0.99
// text = French Toast, number = 1.99
// text = Fruit Basket, number = 2.49
// text = Cereal, number = 0.69
// text = Coffee, number = 0.5
// text = Tea, number = 0.75
//
A more robust solution taking into account @Dúthomhas' comments:
std::stod
exceptions.This solution detects:
#include <boost/algorithm/string.hpp>
#include <fmt/core.h>
#include <iostream> // cout
#include <string> // find_last_of, getline, stod
int main()
{
std::string line{};
while (std::getline(std::cin, line))
{
try
{
boost::trim_right(line);
auto pos{line.find_last_of(' ')};
auto text{line.substr(0, pos)};
auto number{std::stod(line.substr(pos))};
std::cout << "text = " << text << ", number = " << number << "\n";
}
catch (const std::exception&)
{
std::cout << fmt::format("* Error: invalid line '{}'\n", line);
}
}
}
// Outputs:
//
// text = Plain Egg, number = 1.45
// text = Bacon and Egg, number = 2.45
// text = Muffin, number = 0.99
// text = French Toast, number = 1.99
// * Error: invalid line ''
// * Error: invalid line 'Fruit Basket'
// * Error: invalid line '0.75'
// * Error: invalid line 'Coffee blah'
Upvotes: 3
Reputation: 901
Somewhat heavy handed: using the same idea of looking for the last space in string but with trimming spaces left and right. The bad thing is that while it is a lot of code and it still would not work with unicode in any form.
// Right trim the line
while(!line.empty()) {
if (isspace(line.back())) {
line.pop_back();
}
}
// Find the last space
size_t pos = line.find_last_of(" \t");
if (pos == std::string::npos) {
// Bad line: no spaces or only spaces
handle_it();
}
// Get the price
double price = 0.0;
try {
size_t end_pos = 0;
price = std::stod(line.substr(pos), &end_pos);
if ((pos + end_pos) != line.length()) {
// Another bad format: garbage at the end
handle_it();
}
} catch (...) {
// Another bad format
handle_it();
}
// Left trim the item
size_t skip = 0;
while(skip > pos && isspace(line[skip])) {
skip++;
}
if (skip == pos) {
// Another bad format: spaces + price
handle_it();
}
// Right trim the item
// we know that we have at leas one non-space
pos--;
while(isspace(line[pos])) {
pos--;
}
std::string item = line.substr(skip, pos + 1);
Upvotes: 0
Reputation: 1747
You can do this for your given inputs by iterating the string to find the index at which the float value begins. Then grab the substring for each part and cast the value to a float.
#include <iostream>
using namespace std;
int main()
{
string s = "Bacon and Egg 2.45";
int l = 0;
string food;
float val = 0.0;
for (int i = 0; i < s.length(); i++)
{
if(isdigit(s[i]))
{
l = i;
break;
}
}
food = s.substr(0,l);
val = stof(s.substr(l,s.length()));
cout << food << endl;
cout << val;
}
Upvotes: 0