get string after getline() - c++

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

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('-')

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).

I'm going to make a couple assumptions here:
You never expect a '\n' except at the end of the input string, even after "-b" (which your code will currently read in)
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

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

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

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; `

Related

I need to convert some code so that it works with an input and output file text

I have a program that reverses the letters in a sentence but keeps the words in the same order. I need to change the code from an iostream library to an fstream library where the user inputs a sentence into an input file("input.txt") and the program outputs the reverse into an output text file.
example of input:
This problem is too easy for me. I am an amazing programmer. Do you agree?
Example of output:
sihT melborp si oot ysae rof em. I ma na gnizama remmargorp. oD uoy eerga?
The code I already have:
int main()
{
int i=0, j=0, k=0, l=0;
char x[14] = "I LOVE CODING";
char y[14] = {'\0'};
for(i=0; i<=14; i++) {
if(x[i]==' ' || x[i]=='\0') {
for(j=i-1; j>=l; j--)
y[k++] = x[j];
y[k++] = ' ';
l=i+1;
}
}
cout << y;
return 0;
}
I would use std::string to store the string, and benefit from std::vector and const_iterator to make better use of C++ features:
#include <string>
#include <vector>
int main()
{
std::string s("This problem is too easy for me. I am an amazing programmer. Do you agree?");
const char delim = ' ';
std::vector<std::string> v;
std::string tmp;
for(std::string::const_iterator i = s.begin(); i <= s.end(); ++i)
{
if(*i != delim && i != s.end())
{
tmp += *i;
}else
{
v.push_back(tmp);
tmp = "";
}
}
for(std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it)
{
std::string str = *it,b;
for(int i=str.size()-1;i>=0;i--)
b+=str[i];
std::cout << b << " ";
}
std::cout << std::endl;
}
Output:
sihT melborp si oot ysae rof .em I ma na gnizama .remmargorp oD uoy ?eerga
The code that you submitted looks much more like something from C rather than from C++. Not sure if you are familiar std::string and function calls. As the code you wrote is pretty sophisticated, I will assume that you are.
Here is an example of how to use fstream. I almost always you getline for the input because I find that it gets me into fewer problems.
I then almost always use stringstream for parsing the line because it neatly splits the lines at each space.
Finally, I try to figure out a while() or do{}while(); loop that will trigger off of the input from the getline() call.
Note that if the word ends in a punctuation character, to keep the punctuation at the end, the reverse_word() function has to look for non-alpha characters at the end and then save that aside. This could be done by only reversing runs of alphas.
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
///////////////////
/// return true if ch is alpha
/// return false for digits, punctuation, and all else
bool is_letter(char ch){
if((ch >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z')) {
return true;
} else {
return false;
}
}
////////
// Only reverse the letter portion of each word
//
std::string reverse_word(std::string str)
{
std::string output_str; // Probably have to create a copy for output
output_str.reserve(str.length()); // reserve size equal to input string
// iterate through each letter of the string, backwards,
// and copy the letters to the new string
char save_non_alpha = 0;
for (auto it = str.rbegin(); it != str.rend(); it++) {
/// If the last character is punctuation, then save it to paste on the end
if(it == str.rbegin() && !is_letter(*it)) {
save_non_alpha = *it;
} else {
output_str += *it;
}
}
if(save_non_alpha != 0) {
output_str += save_non_alpha;
}
return output_str; // send string back to caller
}
int main()
{
std::string input_file_name{"input.txt"};
std::string output_file_name{"output.txt"};
std::string input_line;
std::ifstream inFile;
std::ofstream outFile;
inFile.open(input_file_name, std::ios::in);
outFile.open(output_file_name, std::ios::out);
// if the file open failed, then exit
if (!inFile.is_open() || !outFile.is_open()) {
std::cout << "File " << input_file_name
<< " or file " << output_file_name
<< " could not be opened...exiting\n";
return -1;
}
while (std::getline(inFile, input_line)) {
std::string word;
std::string sentence;
std::stringstream stream(input_line);
// I just like stringstreams. Process the input_line
// as a series of words from stringstream. Stringstream
// will split on whitespace. Punctuation will be reversed with the
// word that it is touching
while (stream >> word) {
if(!sentence.empty()) // add a space before all but the first word
sentence += " ";
word = reverse_word(word);
sentence += word;
}
outFile << sentence << std::endl;
}
inFile.close();
outFile.close();
return 0;
}

Separate two inputs C++

I have made a quiz helper, but, as I want it for you to be able to input a new question without starting it, I made a do/while loop. The first run goes fine. When it asks you if you want to input another question, if you choose y, it runs the main program too at the same time, and the program registers y as a question. How do I separate this?Code:
#include <cctype>
#include <iostream>
#include <string>
#include "Quiz.h"
#include "Quiz2.h"
char choice;
int main()
{
do{
quiz();
std::cout << "Da li zelite da vam odgovorim na jos jedno pitanje?(y/n)" << std::endl;
std::cin >> choice;
} while(choice != 'n');
}
The first header file just includes the function to find words:
#ifndef QUIZ_H_INCLUDED
#define QUIZ_H_INCLUDED
bool contains_word(const std::string& sentence, const std::string& word)
{
size_t pos = 0;
while ((pos = sentence.substr(pos).find(word)) != std::string::npos) {
if (!(isalpha(sentence[pos - 1])) || !(isalpha(sentence[pos + word.size() + 1])))
return true;
}
return false;
}
#endif
And the other one contains the real code, it is partially in Serbian:
#ifndef QUIZ2_H_INCLUDED
#define QUIZ2_H_INCLUDED
int quiz()
{
std::string sentence;
std::cout << "Ukucajte pitanje ili kljucne reci: " << std::flush;
std::getline(std::cin, sentence);
std::string word ("Belgija");
std::string word2 ("regija");
std::string word3 ("Kanada");
std::string word4 ("teritorija");
std::string word5 ("Holandija");
std::string word6 ("delova");
if (contains_word(sentence, word) && contains_word(sentence, word2))
std::cout << "Odgovor je 3 regije." << std::endl;
else if (contains_word(sentence, word3) && contains_word(sentence, word4))
std::cout << "Odgovor je 3 teritorije." << std::endl;
else if (contains_word(sentence, word5) && contains_word(sentence, word6))
std::cout << "Odgovor je 3 dela." << std::endl;
else
std::cout << "Nisam mogao pronaci odgovor na to pitanje!" << std::endl;
return 0;
}
#endif
Any help is appreciated.
There is a newline character after a choice, so just add cin.ignore:
std::cin >> choice;
std::cin.ignore();
It ignores one character from input.
Alternative solution
Alternatively, you could discard all empty lines in quiz() function - substitute
std::getline(std::cin, sentence);
with
do {
std::getline(std::cin, sentence);
} while( sentence.empty() );
Other issue with the code
The contains_word function should be corrected. You shouldn't get value of sentence[pos + word.size() + 1] if it is possible for the word to be at the very end of sentence (subscript past the end of array).
Similar error in sentence[pos - 1] - what if pos is 0? You get some random stuff before the string.
You have to rework the condition also - certainly if( !(...) || !(...) ) is not what you wanted.
Should be something like this:
bool contains_word(const std::string& sentence, const std::string& word)
{
size_t pos = 0;
while ((pos = sentence.substr(pos).find(word)) != std::string::npos) {
if( (pos == 0 || isalpha(sentence[pos - 1])) &&
(pos + word.size() == sentence.size() || isalpha(sentence[pos + word.size()])) )
return true;
}
return false;
}
getline() and cin don't play well together. After a cin operation there is typically a newline left in the input stream that the getline reads and immediately concludes it is done. You can "solve" the problem by calling getline twice and ignoring the first result. However note that this only happens AFTER a call to cin, so the first time thru you should NOT use getline twice. This is why I say they "don't play well together".

How do you parse a c-string?

Hi I'm trying to take a c-string from a user, input it into a queue, parse the data with a single space depending on its contents, and output the kind of data it is (int, float, word NOT string).
E.g. Bobby Joe is 12 in 3.5 months \n
Word: Bobby
Word: Joe
Word: is
Integer: 12
Word: in
Float: 3.5
Word: months
Here's my code so far:
int main()
{
const int maxSize = 100;
char cstring[maxSize];
std::cout << "\nPlease enter a string: ";
std::cin.getline(cstring, maxSize, '\n');
//Keyboard Buffer Function
buffer::keyboard_parser(cstring);
return EXIT_SUCCESS;
}
Function:
#include <queue>
#include <string>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
namespace buffer
{
std::string keyboard_parser(char* input)
{
//Declare Queue
std::queue<std::string> myQueue;
//Declare String
std::string str;
//Declare iStringStream
std::istringstream isstr(input);
//While Loop to Read iStringStream to Queue
while(isstr >> str)
{
//Push onto Queue
myQueue.push(str);
std::string foundDataType = " ";
//Determine if Int, Float, or Word
for(int index = 0; index < str.length(); index++)
{
if(str[index] >= '0' && str[index] <= '9')
{
foundDataType = "Integer";
}
else if(str[index] >= '0' && str[index] <= '9' || str[index] == '.')
{
foundDataType = "Float";
break;
}
else if(!(str[index] >= '0' && str[index] <= '9'))
{
foundDataType = "Word";
}
}
std::cout << "\n" << foundDataType << ": " << myQueue.front();
std::cout << "\n";
//Pop Off of Queue
myQueue.pop();
}
}
}
Right now with this code, it doesn't hit the cout statement, it dumps the core.
I've read about using the find member function and the substr member function, but I'm unsure of how exactly I need to implement it.
Note: This is homework.
Thanks in advance!
UPDATE: Okay everything seems to work! Fixed the float and integer issue with a break statement. Thanks to everyone for all the help!
Your queue is sensible: it contains std::strings. Unfortunately, each of those is initialised by you passing cstring in without any length information and, since you certainly aren't null-terminating the C-strings (in fact, you're going one-off-the-end of each one), that's seriously asking for trouble.
Read directly into a std::string.
std::istreams are very useful for parsing text in C++... often with an initial read of a line from a string, then further parsing from a std::istringstream constructed with the line content.
const char* token_type(const std::string& token)
{
// if I was really doing this, I'd use templates to avoid near-identical code
// but this is an easier-to-understand starting point...
{
std::istringstream iss(token);
int i;
char c;
if (iss >> i && !(iss >> c)) return "Integer";
}
{
std::istringstream iss(token);
float f;
char c; // used to check there's no trailing characters that aren't part
// of the float value... e.g. "1Q" is not a float (rather, "word").
if (iss >> f && !(iss >> c)) return "Float";
}
return "Word";
}
const int maxSize = 100; // Standard C++ won't let you create an array unless const
char cstring[maxSize];
std::cout << "\nPlease enter a string: ";
if (std::cin.getline(cstring, maxSize, '\n'))
{
std::istringstream iss(cstring);
std::string token;
while (iss >> token) // by default, streaming into std::string takes a space-...
token_queue.push(token); // ...separated word at a time
for (token_queue::const_iterator i = token_queue.begin();
i != token_queue.end(); ++i)
std::cout << token_type(*i) << ": " << *i << '\n';
}

How to check if the input is a valid integer without any other chars?

#include <iostream>
#include <limits>
using namespace std;
int main()
{
int x;
cout << "5 + 4 = ";
while(!(cin >> x)){
cout << "Error, please try again." << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
if (x == (5 + 4)){
cout << "Correct!" << endl;
}
else{
cout << "Wrong!" << endl;
}
return 0;
}
How can I check if the user inputs a valid integer? In this program I wrote above, if the user inputs 9, it should be correct, however, if the user inputs 9a for example, it should return an error, but it doesn't for some reason. How can I correct it?
How I did it using cin.peek()
#include <iostream>
#include <limits>
#include <stdio.h>
using namespace std;
int main()
{
int x;
bool ok;
cout << "5 + 4 = ";
cin >> x;
while(!ok){
cin >> x;
if(!cin.fail() && (cin.peek() == EOF || cin.peek() == '\n')){
ok = true;
}
else{
cout << "Error, please try again." << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
if (x == (5 + 4)){
cout << "Correct!" << endl;
}
else{
cout << "Wrong!" << endl;
}
return 0;
}
You could read a string, extract an integer from it and then make sure there's nothing left:
std::string line;
std::cin >> line;
std::istringstream s(line);
int x;
if (!(s >> x)) {
// Error, not a number
}
char c;
if (s >> c) {
// Error, there was something past the number
}
bool isIntegerNumber(const std::string& string){
std::string::const_iterator it = string.begin();
int minSize = 0;
if(string.size()>0 && (string[0] == '-' || string[0] == '+')){
it++;
minSize++;
}
while (it != string.end() && std::isdigit(*it)) ++it;
return string.size()>minSize && it == string.end();
}
You have a line oriented input, so you should probably be using
getline. Something like:
bool
getIntFromLine( std::istream& source, int& results )
{
std::string line;
std::getline( source, line );
std::istringstream parse( source ? line : "" );
return parse >> results >> std::ws && parse.get() == EOF;
}
should do the trick.
Using this, your loop would be:
while ( !getIntFromLine( std::istream, x ) ) {
std::cout << "Error, please try again." << std::endl;
}
Note that this technique also means that you don't have to worry
about clearing the error or resynchronizing the input.
For the reason this happens, take a look at this link:
Extracts and parses characters sequentially from the stream to
interpret them as the representation of a value of the proper type,
which is stored as the value of val. Internally, the function accesses
the input sequence by first constructing a sentry object (with
noskipws set to false). Then (if good), it calls num_get::get (using
the stream's selected locale) to perform both the extraction and the
parsing operations, adjusting the stream's internal state flags
accordingly. Finally, it destroys the sentry object before returning.
Then observe the behavior if you attempt something like this:
int x = 0;
cin >> x;
std::cout << x << std::endl;
std::cout << cin.good() << std::endl;
g++-4.8 -std=c++11 -O3 -Wall -pedantic -pthread main.cpp && echo "900a100" | ./a.out
// Output:
// 900
// 1
If you input "a100" instead, it outputs:
0
0
try this:
std::string input;
std::cin >> input;
if ( std::all_of(input.begin(), input.end(), std::isdigit) )
{
//input is integer
}
Refer this :
C++ Fix for checking if input is an integer
One I have seen that works for some situations is:
Read the input as string. cin >> str
Decode to number: atoi, or sscanf, or stringstream, etc.
print the number into a string (using sprintf or stringstream)
check if its equal to read string. (using strings ==, not char*)
Quick and simple to do. Uses the Cin>>str word breaking rules, accept negative numbers, rejects overflowing numbers. But it does reject "+10", which in somesituations you are happy wiht, and in some you are not.
If you can use C++11 (and your compiler has full regex support), you can also use the <regex> library:
#include <iostream>
#include <limits>
#include <regex>
#include <string>
#include <utility>
int main()
{
std::string line;
std::pair<int, bool> value = std::make_pair(0, false);
std::cout << "5 + 4 = ";
while (!value.second)
{
while (!std::getline(std::cin, line))
{
std::cout << "Error, please try again." << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
if (!std::regex_match(line, std::regex("(\\+|-)?[[:digit:]]+")))
{
std::cout << "Error, please try again." << std::endl;
}
else
{
value = std::make_pair(std::stol(line), true);
}
}
if (value.first == (5 + 4))
{
std::cout << "Correct!" << std::endl;
}
else
{
std::cout << "Incorrect!" << std::endl;
}
return 0;
}

Why doesn't this code run?

Hey, sorry if this is asked a lot but I have no idea what the problem here is.
In the C++ code below, I'm reading from a user defined input file and generating output. I've been writing it piece by piece and putting it together, compiling, testing, etc as I go to work out the bugs. This is a learning experience for me, first self-directed program I guess...
Anyways, when I run the code, the command prompt prints ONE line and goes unresponsive. I would say it has been caught in some kind of loop, but I believe that's impossible.
I think it might have something to do with the array I'm trying to declare, I wanted to make a dynamic string array but I found out that's difficult...
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cctype>
#include <string>
using namespace std;
int wordCount(string line)
{
int fpos, fpos2;
int count = 0;
fpos = line.find_first_not_of(' ');
line.erase(0, fpos);
while(line.size() > 0)
{
fpos = line.find_first_of(' ');
if(line.at(0) == '"')
{
line.erase(0, 1);
for(int i = 0; i <line.size(); i++)
if(line.at(i) == '"' && line.at(i-1) != '\\')
{
fpos2 = i;
break;
}
line.erase(0, fpos2 + 2);
}
else
line.erase(0, fpos + 1);
count++;
}
return count;
}
int main()
{
//Current line; Input file; Output file;
string currentline, fileName, outFileName;
ifstream fin;
ofstream fout;
cout << "Enter input file name: ";
getline(cin, fileName);
cout << "Enter output file name: ";
getline(cin, outFileName);
fin.open(fileName.c_str());
if (!fin.good()) throw "I/O error";
fout.open(outFileName.c_str());
if (!fout.good()) throw "I/O error";
getline(fin, currentline);
while (!currentline.empty())
{
int pos, pos1;
pos = currentline.find("//");
string postScript = currentline.substr(pos+2,-1);
pos = currentline.find_first_of(';');
string xline = currentline.substr(0,pos+1);
cout << xline << endl;
int size = wordCount(xline);
string *words;
words = (string *) malloc (size*sizeof(string));
words = new string[size];
pos = xline.find_first_not_of(' ');
xline.erase(0, pos);
for ( int i = 0; i < size; i++ )
{
pos = xline.find_first_of(' ');
if ( xline.at(0) == '"' )
{
xline.erase(0, 1);
for(int a = 0; a < xline.size(); a++) //This for loop finds the end of a quoted statement within the line.
if ( xline.at(a) == '"' && xline.at(a-1) != '\\' )
{
pos = a;
break;
}
words[i] = xline.substr(0,pos);
xline.erase(0,pos + 2);
}
else
{
words[i] = xline.substr(0,pos);
xline.erase(0,pos + 1);
}
cout << words[i] << endl;
}
cout << xline << endl << endl;
getline(fin, currentline);
}
return 0;
}
I would suggest you commenting out bits of code until it starts to work the way you expect (Usually the problematic bit will become obvious this way.) Once you figure out what is wrong you can ask a more specific question on StackOverflow.
You should use a debugger to investigate the program behavior.
To avoid single stepping the whole program, you can set breakpoints where you expect to passs the sequence. When a breakpoint is not hit you can use single stepping from the previous point. Additionally you can look at variables content.
It never finds the end quote:
if ( xline.at(a) == '"' && xline.at(a-1) != '\\' )
{
pos = a;
break;
}
Try this instead:
if (xline.at(a) == '"')
{
pos = a;
break;
}
You only need to escape " if its contained in a string literal, e.g. "There's a \" in this literal"