Reputation: 1200
If I have a line of input string from std::cin
which consists of strings and ints separated by whitespaces. What is the most effective way to get them separated and stored?
e.g:
input: "Move 1 to 2"
variables for storing:
string a, b;
int orig, dest;
Edit:
I have applied the following code as suggested. However, when I input "move 9 onto 1", it seems that only the word "move" is properly stored in the vector strs.
string command;
cin >> command;
vector<int> ints;
vector<string> strs;
string strval;
int intval;
stringstream test;
test.str(command);
while(true) {
if(test.eof())
break;
if(test >> strval) {
strs.push_back(strval);
}
else if(test >> intval) {
ints.push_back(intval);
}
else {
cout << "error!" << endl;
}
}
Problem Solved:
use
getline(cin, command);
instead of
cin >> command;
Upvotes: 2
Views: 4267
Reputation: 393039
You're looking for parsing text.
Your "input grammar" is... underspecified, but here goes with a Parser framework like e.g. Boost Spirit:
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct Command { std::string name; int a, b; };
BOOST_FUSION_ADAPT_STRUCT(Command, (std::string, name)(int,a)(int,b))
int main()
{
const std::string input("Move 2 to 4");
auto f(begin(input)), l(end(input));
Command parsed;
bool ok = qi::phrase_parse(f,l,
qi::string("Move") >> qi::int_ >> "to" >> qi::int_
| qi::string("Multiply") >> qi::int_ >> "by" >> qi::int_
| qi::string("Subtract") >> qi::int_ >> "from" >> qi::int_
, qi::space, parsed);
if (ok)
{
std::cout << "parse success\n";
std::cout << "parsed: '" << parsed.name << "' with (" << parsed.a << ", " << parsed.b << ")" << "\n";
}
else std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
}
Prints
parse success
parsed: 'Move' with (2, 4)
Upvotes: 1
Reputation: 8886
I'm going to assume the order of ints and strings is unknown. You can exploit the conversion of cin
to bool to decide whether you have detected an int or not.
Basically, (cin >> intValue)
(where intValue
is an int
) is an expression which returns true
if the next few characters constitute a valid number that can fit into an int
, and false
otherwise. Same principle applies for other types such as string
. These can be used in if-statements such as
int intValue;
if (cin >> intValue) { //evaluates to true or false
// do something
} else {
// do something else
}
You can use this with a while-loop to parse your whole input, like so:
vector<int> ints; //container to store ints
vector<string> strings; //container to store ints
while(true) {
int intValue;
string stringValue;
if(cin.eof()) //exit the loop when the end of the input is reached
break;
if(cin >> intValue) { //if this is true, then an int was successfully read into intValue
ints.push_back(intValue);
} else if (cin >> stringValue) { //if this is true, int could not be read but string was successfully read
strings.push_back(stringValue);
} else {
cout << "Error: unknown value read in, not recognized as int or string" << endl;
exit(-1);
}
}
I just read that you already have the line as a string. The same solution above will work, just use stringstream instead of cin:
string line; //the line that you already have, initialized elsewhere
stringstream ss(line.str()); //convert the line to a stringstream, treat it similar to cin
vector<int> ints; //container to store ints
vector<string> strings; //container to store strings
while(true) {
int intValue;
string stringValue;
if(ss.eof())
break;
if(ss >> intValue) {
ints.push_back(intValue);
} else if (ss >> stringValue) {
strings.push_back(stringValue);
} else {
cout << "Error: unknown value read in, not recognized as int or string" << endl;
exit(-1);
}
}
In your example, which was the line Move 1 to 2
, The vector will contain 1
and 2
, and the vector will contain Move
and to
.
Upvotes: 2