简体   繁体   中英

C++ Splitting a string into strings and ints

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?

eg:

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;

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);
  }
}

Edit:

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 .

You're looking for parsing text.

Your "input grammar" is... underspecified, but here goes with a Parser framework like eg 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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM