notimportant
notimportant

Reputation: 11

get string after getline()

I want to hold a string with spaces therefore I used getline() but after it I want to get another string(no spaces) if there is a -e for example and the string after it in s2, but since in my code I lose the dash when using getline() I can't seem to achieve what I'm trying to do. any suggestions would be really helpful.

//example input: -f name -b blah blah -e email
//looking for output:
//name 
//blah blah
//email


string s,s1,s2;
char check_character;

while (cin.peek() != '\n')
{
    if (cin.get() == '-')
    {
        check_character = cin.get();
        switch(check_character)
        {
            case 'f':
            cin >> s;
            break;
            case 'b':
            if(cin.peek() != '\n')
                getline(cin, s1, '-');
            else if(cin.peek() =='\n')
                getline(cin, s1);
            break;
            case 'e':
            cin>> s2;
            break;
        }
    }
}
cout << s << endl << s1 << endl << s2 << endl;
return 0; 

}

Upvotes: 1

Views: 1980

Answers (6)

user9564518
user9564518

Reputation:

I think you should put cin.ignore before typing getline as in your code:

`string s,s1,s2;
char check_character;

while (cin.peek() != '\n')
 {
    if (cin.get() == '-')
 {
    check_character = cin.get();
    switch(check_character)
    {
        case 'f':
        cin >> s;
        break;
        case 'b':
        if(cin.peek() != '\n')
            cin.ignore
            getline(cin, s1, '-');
        else if(cin.peek() =='\n')
            cin.ignore
            getline(cin, s1);
        break;
        case 'e':
        cin>> s2;
        break;
    }
}
}
cout << s << endl << s1 << endl << s2 << endl;
return 0; `

Upvotes: 0

Killzone Kid
Killzone Kid

Reputation: 6240

The way you parse the arguments could certainly be improved, but this answer is not about it. I think what you are looking for is to simply put the - char back into the stream after std::getline removed it. In this case you could just use .putback() method

if (std::cin.peek() != '\n')
{
    std::getline(std::cin, s1, '-');
    std::cin.putback('-');
}

Upvotes: 0

Eljay
Eljay

Reputation: 5321

If you go the approach of reading in the entire line, and you do not want to use Boost program options, or getopts, you could parse the line yourself (as has been suggested). Here would be one way of doing it, as an alternative of parsing on the fly in your code:

#include <iostream>
#include <string>
#include <tuple>
#include <vector>

using std::cout;
using std::endl;
using std::get;
using std::literals::string_literals::operator""s;
using std::make_tuple;
using std::string;
using std::tuple;
using std::vector;

static auto chunkLine(string const& line)
{
  auto result = vector<string>{};
  auto i = string::size_type{};
  while (i != string::npos && i < line.size())
  {
    auto pos = line.find(" -", i);
    auto count = pos == string::npos ? pos : (pos - i);
    result.push_back(line.substr(i, count));
    i = pos + (pos != string::npos ? 1 : 0);
  }
  return result;
}

static auto parseChunks(vector<string> const& chunks)
{
  auto result = vector<tuple<string, string>>{};
  for (auto const& chunk : chunks)
  {
    auto pos = chunk.find(" ");
    if (pos != string::npos && chunk[0] == '-')
    {
      auto kv = make_tuple(chunk.substr(1, pos-1), chunk.substr(pos+1));
      result.push_back(kv);
    }
  }
  return result;
}

int main()
{
  auto line = "-f name -b blah blah -e email"s;
  auto keyValueTuples = parseChunks(chunkLine(line));
  for (auto const& kv : keyValueTuples)
  {
    cout << get<1>(kv) << endl;
  }
}

Upvotes: 0

Jonathan Mee
Jonathan Mee

Reputation: 38969

I'm going to make a couple assumptions here:

  1. You never expect a '\n' except at the end of the input string, even after "-b" (which your code will currently read in)
  2. You expect to only accept 1 of each type of argument (cause your current code will stomp any previous entries)

A regex_search will handle this nicely with the regex:

(?:\s*-f\s+(\w+)|\s*-b\s+([^-]+)|\s*-e\s+(\w+))*

Live Example

You'll need to start by reading from cin into a variable, for example string input. This could be done like:

getline(cin, input)

Once you have your input you can simply do:

if(smatch m; regex_search(input, m, regex{ "(?:\\s*-f\\s+(\\w+)|\\s*-b\\s+([^-]+)|\\s*-e\\s+(\\w+))*" })) {
    if(m[1].length() > 0U) {
        cout << "-f " << m[1] << endl;
    }

    if(m[2].length() > 0U) {
        cout << "-b " << m[2] << endl;
    }

    if(m[3].length() > 0U) {
        cout << "-e " << m[3] << endl;
    }
}

Live Example

Upvotes: 0

BJ Makruk
BJ Makruk

Reputation: 46

getline() extracts characters from is and stores them into str until the delimitation character delim is found or the newline character, '\n'.

If the delimiter is found, it is extracted and discarded (i.e. it is not stored and the next input operation will begin after it).

Upvotes: 1

Eyal Cinamon
Eyal Cinamon

Reputation: 959

A better option would be to do a single call to getline() then parse the "command" string. There are many options of achieving this, from a simple split() on "-" or find('-')

Upvotes: 1

Related Questions