1

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.

Falcon
  • 37
  • 3

1 Answers1

1

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

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thankyou for your valuable inputs.Below is my code with the logic shared by you, where I am iterating based on number of inputs but then I receive runtime error. How to fix the same. https://ideone.com/XfwMqc – Falcon Jul 18 '22 at 13:47
  • @Falcon you are running into this issue: [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/) After `std::cin >> noOfInput;` there is an unread line break left behind in `cin`'s input buffer that causes the next `std::getline(std::cin, line);` to return an empty string in `line`. You need to discard that unread line break after reading in `noOfInput`. – Remy Lebeau Jul 18 '22 at 17:33
  • 1
    Yes I have gone through that link before, cin.ignore() doesn't work in my case. It still behaves same with or without it. – Falcon Jul 18 '22 at 18:33
  • `int noOfInput; std::cin >> noOfInput; ... std::getline(std::cin, line);` will not work in your example, `line` will be empty. You need either `int noOfInput; std::cin >> noOfInput; std::cin.ignore(std::numeric_limits::max(), '\n'); ... std::getline(std::cin, line);` Or `int noOfInput; std::cin >> noOfInput; ... std::getline(std::cin >> std::ws, line);` – Remy Lebeau Jul 18 '22 at 18:58
  • 1
    After fixing that, I see your `for` reading loop is also wrong, it needs to use `<` instead of `<=`. Also, `line.find_first_not_of(" ", ...)` could just be `line.find(' ', ...)` since you are looking for just spaces. The example I gave you looks for both spaces and tabs instead. But either way, I see you are parsing the items correctly, but `discountMap.find(item.name)` is not finding them, hence the `Invalid Item for Promotion` errors, because you commented out `init()` in `main()` to populate `discountMap`. Uncommenting that, I don't get any more errors: https://ideone.com/iMfD8W – Remy Lebeau Jul 18 '22 at 19:07