putting into consideration the argument between quotation marks - c++

I am trying to parse a command line string, at every white space putting into consideration the string has words between quotation marks. I want to store whatever is between 2 quotation marks as 1 index in a vector.
vector<string> words;
stringstream ss(userInput);
string currentWord;
vector<string> startWith;
stringstream sw(userInput);
while (getline(sw, currentWord, ' '))
words.push_back(currentWord);
while (getline(ss, currentWord, '"'))
startWith.push_back(currentWord); //if(currentWord.compare("")){ continue;}
for (int i = 0; i < startWith.size(); i++)
curr
if(currentWord.compare("")){ continue;}
cout << " Index "<< i << ": " << startWith[i] << "\n";

It is not clear what you're trying to do. Here's a starting point (run it):
#include <iostream>
#include <sstream>
#include <string>
std::istream& get_word_or_quote( std::istream& is, std::string& s )
{
char c;
// skip ws and get the first character
if ( !std::ws( is ) || !is.get( c ) )
return is;
// if it is a word
if ( c != '"' )
{
is.putback( c );
return is >> s;
}
// if it is a quote (no escape sequence)
std::string q;
while ( is.get( c ) && c != '"' )
q += c;
if ( c != '"' )
throw "closing quote expected";
//
s = std::move( q );
return is;
}
int main()
{
std::istringstream is {"not-quoted \"quoted\" \"quoted with spaces\" \"no closing quote!" };
try
{
std::string word;
while ( get_word_or_quote( is, word ) )
std::cout << word << std::endl;
}
catch ( const char* e )
{
std::cout << "ERROR: " << e;
}
return 0;
}
The expected output is:
not-quoted
quoted
quoted with spaces
ERROR: closing quote expected

Related

Readin a line from console c++

I am new to c++ and I am a bit lost here!
I am trying to read the following line
* - 6 + x -6 - - 9 6 * 0 c
and I am iterating through the characters using
for (std::string line; std::getline(std::cin, line);) {
for(auto c : line){
if(c != ' ')
}
}
now I am expecting to get "-6" at the sixth iteration but a I am getting "-" and then at the next iteration I am getting 6, I need to get "-6"! any help!
In the outer for loop, you are infinitely looping until getline() evaluates to false. In the inner for loop, you are looping through each character in line.
I don't know of any elegant syntax to parse a string into tokens like it seems you are trying to do. One way is to utilise std::stringstream and put things into an array or vector. Below is a sample main I wrote demonstrating how versatile this is:
#include <iostream>
#include <sstream>
#include <vector>
int main() {
std::string line;
while ( true ) {
std::cout << "Enter parse string: ";
std::getline( std::cin, line );
if ( line == "Stop" ) break; // Enter stop to quit program
std::stringstream ss( line ); // constructor sets 'line' as contents of the stream
std::vector <std::string> tokens; // where our tokenised input is stored
std::string temp; // where current token is temporarily loaded before it's put into the vector
while( getline( ss, temp, ' ' ) ) // extract characters from ss until a space is found and stores them in temp
tokens.push_back( temp ); // put the token formed by getline in our vector, from back so order is kept
/*
Now you can use the vector as you would like. Below the contents are printed.
*/
for ( auto& x : tokens ) // for each token in 'tokens' vector,
std::cout << x << ' '; // print out token with a space at the end
std::cout << "\n\n";
for ( int i = 0; i < tokens.size(); i++ ) // for each token in 'tokens' vector,
std::cout << i << ": " << tokens[i] << '\n'; // print out index number and token
std::cout << std::endl; // newline & flush
}
return 0;
}
If you want to abstract the details away, you could always wrap the std::stringstream stuff into a function that takes in a string and returns a std::vector<std::string>. Below I demonstrate what that would look like:
#include <iostream>
#include <sstream>
#include <vector>
std::vector <std::string> toParsedVector( std::string input ) {
std::stringstream ss( input ); // constructor sets 'line' as contents of the stream
std::vector <std::string> tokens; // where our tokenised input is stored
std::string temp; // where current token is temporarily loaded before it's put into the vector
while( getline( ss, temp, ' ' ) ) // extract characters from ss until a space is found and stores them in temp
tokens.push_back( temp ); // put the token formed by getline in our vector, from back so order is kept
return tokens;
}
int main() {
std::string line;
while ( true ) {
std::cout << "Enter parse string: ";
std::getline( std::cin, line );
if ( line == "Stop" ) break; // Enter stop to quit program
std::vector <std::string> tokens = toParsedVector( line ); // create vector
// Now you can use the vector (tokens) as you would like. Below the contents are printed.
for ( auto& x : tokens ) // for each token in 'tokens' vector,
std::cout << x << ' '; // print out token with a space at the end
std::cout << "\n\n";
for ( int i = 0; i < tokens.size(); i++ ) // for each token in 'tokens' vector,
std::cout << i << ": " << tokens[i] << '\n'; // print out index number and token
std::cout << std::endl; // newline & flush
}
return 0;
}
I hope this helps; might not be the most elegant solution, but it is very versatile.

Split a sentence (string) at the spaces [duplicate]

This question already has answers here:
How do I iterate over the words of a string?
(84 answers)
Closed 5 years ago.
I am trying to split a single string, with spaces, into three separate strings. For example, I have one string (str1). The user inputs any 3 words such as
"Hey it's me" or "It's hot out".
From there, I need to write a function that will take this string (str1) and divide it up into three different strings. So that (taking the first example) it will then say:
Hey (is the first part of the string)
it's (is the second part of the string)
me (is the third part of the string)
I'm having difficulty which manipulation I should be using to split the string at the spaces.
This is the code I have so far, which is just how the user will enter input.I am looking for the most basic way to accomplish this WITHOUT using istringstream! Using only basic string manipulation such as find(), substr().
** I am looking to create a separate function to perform the breaking up of string ** I figured out how to get the first section of input with this code:
cout << "Enter a string" << endl;
getline(cin, one);
position = str1.find(' ', position);
first_section = str1.substr(0, position);
But now I have no idea how to get the second section or the third section of the string to be divided up into their own string. I was thinking a for loop maybe?? Not sure.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1;
cout << "Enter three words: ";
getline(cin, str1);
while(cin) {
cout << "Original string: " << str1 << endl;
cin >> str1;
}
return;
}
I'm having difficulty which manipulation I should be using to split the string at the spaces.
Use a std::istringstream from str1.
Read each of the tokens from the std::istringstream.
// No need to use a while loop unless you wish to do the same
// thing for multiple lines.
// while(cin) {
cout << "Original string: " << str1 << endl;
std::istringstream stream(str1);
std::string token1;
std::string token2;
std::string token3;
stream >> token1 >> token2 >> token3;
// Use the tokens anyway you wish
// }
If you wish to do the same thing for multiple lines of input, use:
int main() {
string str1;
cout << "Enter three words: ";
while(getline(cin, str1))
{
cout << "Original string: " << str1 << endl;
std::istringstream stream(str1);
std::string token1;
std::string token2;
std::string token3;
stream >> token1 >> token2 >> token3;
// Use the tokens anyway you wish
// Prompt the user for another line
cout << "Enter three words: ";
}
}
Perhaps the most basic solution is to use that which resides inside of your loop to read a single word. For example:
cin >> word1; // extracts the first word
cin >> word2; // extracts the second word
getline(cin, line); // extracts the rest of the line
You can use the result or return value of these expressions to check success:
#include <string>
#include <iostream>
int main(void) {
std::string word1, word2, line;
int success = std::cin >> word1 && std::cin >> word2
&& !!std::getline(std::cin, line); // double-! necessary?
if (success) { std::cout << "GOOD NEWS!" << std::endl; }
else { std::cout << "bad news :(" << std::endl; }
return 0;
}
Alternatively, in such a string I would expect two spaces. My suggestion would be to use string::find to locate the first and second spaces like so:
size_t first_position = str1.find(' ', 0);
You should probably check this against string::npos as an opportunity to handle errors. Following that:
size_t second_position = str1.find(' ', first_position + 1);
Next error handling check and after that, it should then be trivial to use string::substr to split that string into sections like so:
string first_section = str1.substr(0 , first_position)
, second_section = str1.substr(first_position , second_position)
, third_section = str1.substr(second_position, string::npos);
I have this Utility class that has a bunch of methods for string manipulation. I will show the class function for splitting strings with a delimiter. This class has private constructor so you can not create an instance of this class. All the methods are static methods.
Utility.h
#ifndef UTILITY_H
#define UTILITY_h
// Library Includes Here: vector, string etc.
class Utility {
public:
static std::vector<std::string> splitString( const std::string& strStringToSplit,
const std::string& strDelimiter,
const bool keepEmpty = true );
private:
Utility();
};
Utility.cpp
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit,
const std::string& strDelimiter,
const bool keepEmpty ) {
std::vector<std::string> vResult;
if ( strDelimiter.empty() ) {
vResult.push_back( strStringToSplit );
return vResult;
}
std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
while ( true ) {
itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
std::string strTemp( itSubStrStart, itSubStrEnd );
if ( keepEmpty || !strTemp.empty() ) {
vResult.push_back( strTemp );
}
if ( itSubStrEnd == strStringToSplit.end() ) {
break;
}
itSubStrStart = itSubStrEnd + strDelimiter.size();
}
return vResult;
}
Main.cpp -- Usage
#include <string>
#include <vector>
#include "Utility.h"
int main() {
std::string myString( "Hello World How Are You Today" );
std::vector<std::string> vStrings = Utility::splitString( myString, " " );
// Check Vector Of Strings
for ( unsigned n = 0; n < vStrings.size(); ++n ) {
std::cout << vStrings[n] << " ";
}
std::cout << std::endl;
// The Delimiter is also not restricted to just a single character
std::string myString2( "Hello, World, How, Are, You, Today" );
// Clear Out Vector
vStrings.clear();
vStrings = Utility::splitString( myString2, ", " ); // Delimiter = Comma & Space
// Test Vector Again
for ( unsigned n = 0; n < vStrings.size(); ++n ) {
std::cout << vStrings[n] << " ";
}
std::cout << std::endl;
return 0;
}

Reading from file in C++, dealing with blanks

I am tying to read from a text file in C++98. It has a pattern, but sometimes a field is empty:
ID Name Grade level
1 a 80 A
2 b B
3 c 90 A
How can I read from file such that I can ignore the blanks?
( I wish I could simply use Regex: \d*)
Is there any simple way of doing that?
You need to use what knowledge you have about the input to make assumptions about what is missing. You can use std::stringstream to parse individual terms from a text line. In other words std::stringstream deals with blanks by ignoring spaces and getting a complete term only, for example std::stringstream("aaa bbb") >> a >> b will load strings a with "aaa" and b with "bbb".
Here is an example program that parses the input, making a robust parser from scratch can be difficult, but if your input is strict and you know exactly what to expect then you can get away with some simple code:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
//-----------------------------------------------------------------------------
// holds a data entry
struct Entry {
int id;
std::string name;
int grade;
std::string level;
Entry() {
// default values, if they are missing.
id = 0;
name = "Unknown";
grade = 0;
level = "?";
}
void ParseFromStream( std::stringstream &line ) {
std::string s;
line >> s;
if( s[0] >= '0' && s[0] <= '9' ) {
// a number, this is the ID.
id = atoi( s.c_str() );
// get next term
if( line.eof() ) return;
line >> s;
}
if( s[0] >= 'a' && s[0] <= 'z' || s[0] >= 'A' && s[0] <= 'Z' ) {
// a letter, this is the name
name = s;
// get next term
if( line.eof() ) return;
line >> s;
}
if( s[0] >= '0' && s[0] <= '9' ) {
// a number, this is the grade
grade = atoi( s.c_str() );
// get next term
if( line.eof() ) return;
line >> s;
}
// last term, must be level
level = s;
}
};
//-----------------------------------------------------------------------------
int main(void)
{
std::ifstream input( "test.txt" );
std::string line;
std::getline( input, line ); // (ignore text header)
while( !input.eof() ) {
Entry entry;
std::getline( input, line ); // skip header
if( line == "" ) continue; // skip empty lines.
entry.ParseFromStream( std::stringstream( line ));
std::cout << entry.id << ' ' << entry.name << ' ' <<
entry.grade << ' ' << entry.level << std::endl;
}
return 0;
}

istream_iterator behaviour

I have two pieces of code.They work properly when it is used alone in the main().
vector<int> v;
cout << "Enter sequance of integers "<< "(press q to quit) : ";
istream_iterator<int> start_cin(cin);
istream_iterator<int> end_of_cin;
copy(start_cin,end_of_cin,back_inserter(v));
for ( vector<int>::iterator It = v.begin();It != v.end(); It++ )
cout << *It << "\t";
cout << endl;
and
vector<string> vS;
cout << "Enter three strings : ";
for ( int i = 0; i < 3; i++ )
vS.push_back(*istream_iterator<string>(cin));
ostream_iterator<string> sIt(cout,", ");
copy(vS.begin(),vS.end(),sIt);
cout << endl;
When these two part use together,i.e
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
using namespace std;
int main ()
{
// first part
vector<int> v;
cout << "Enter sequance of integers "<< "(press q to quit) : ";
istream_iterator<int> start_cin(cin);
istream_iterator<int> end_of_cin;
copy(start_cin,end_of_cin,back_inserter(v));
for ( vector<int>::iterator It = v.begin();It != v.end(); It++ )
cout << *It << " \t";
cout << endl;
vector<string> vS;
cout << "Enter three strings : ";
for ( int i = 0; i < 3; i++ )
vS.push_back(*istream_iterator<string>(cin));
ostream_iterator<string> sIt(cout,", ");
copy(vS.begin(),vS.end(),sIt);
cout << endl;
return 0;
}
here first part worked but second part give output: Enter Three Strings : , , ,.
I want to know that what is the reason behind this behaviour?
Thanks.
After the copy() has completed cin will be in an unreadable state (!cin.good()), due to the failed read of the "integer" q. This means the subsequent for loop will fail to read anything.
Add:
cin.clear();
cin.ignore(); // To skip the unread "q"
before the for loop.
EDIT:
As commented by James Kanze, check to ensure "q" was the cause of the termination of the copy():
...
cin.clear();
string int_read_terminator;
cin >> int_read_terminator;
if ("q" != int_read_terminator)
{
cerr << "Integer copy() failure: " << int_read_terminator << "\n";
}
else
{
...
You've just encountered one of the problems with input_iterator: it
requires the entire file to be of one type. There are several ways of
working around this; the most general is to insert a filtering streambuf
between the actual source and the stream. Thus, for example, the first
part of your stream should terminate when you enter a single line with
just a 'q', something like:
class UntilQStreambuf : public std::streambuf
{
std::streambuf* mySource;
char myBuffer;
bool myIsAtStartOfLine;
protected:
int underflow()
{
int results = mySource->sbumpc();
if ( results == 'q'
&& myIsAtStartOfLine
&& mySource->sgetc() == '\n' ) {
mySource->sbumpc(); // remove terminator line.
results = traits_type::eof();
}
if ( results != traits_type::eof() ) {
myBuffer = results;
setg( &myBuffer, &myBuffer, &myBuffer + 1 );
}
return results;
}
public:
UntilQStreambuf( std::istream& source )
: mySource( source->rdbuf() )
, myIsAtStartOfLine( true )
{
}
};
(I think boost::iostream has some support which would make this
significantly simpler to write.) You then set up a separate stream for
reading the numbers, using the streambuf from std::cin (or
whereever):
std::vector<int>
getNumbers( std::istream& source )
{
UntilQStreambuf localSB( source );
std::istream src( &localSB );
std::vector<int> results( (std::istream_iterator<int>( src )),
(std::istream_iterator<int>()) );
if ( !src.eof() ) {
// Some other error occurred...
}
return results;
}
By using a separate stream, the end condition won't be set in the
original stream, and you can continue with it later (perhaps using more
of the same technique).

Reading a line with integers and a string with spaces

I've an input formatted like this:
integer multi-word-string integer
I know the maximum lenght of multi-word-string, however I don't know how many words it contains. How can I read it ?
I'd read the line first and convert the first and last word to integers. Loosely:
std::string line;
std::getline(infile, line);
size_t ofs_front = line.find(' ');
size_t ofs_back = line.rfind(' ');
int front = std::strtol(line.substr(0, ofs_front).c_str(), NULL, 0);
int back = std::strtol(line.substr(ofs_back).c_str(), NULL, 0);
std::string text = line.substr(ofs_front, ofs_back - ofs_front);
You'll have to do some modifications to get rid of spaces (e.g. increment the offsets to gobble up all spaces), and you should add lots of error checking.
If you want to normalize all the interior spaces inside the text, then there's another solution using string streams:
std::vector<std::string> tokens;
{
std::istringstream iss(line);
std::string token;
while (iss >> token) tokens.push_back(token);
}
// process tokens.front() and tokens.back() for the integers, as above
std::string text = tokens[1];
for (std::size_t i = 2; i + 1 < tokens.size(); ++i) text += " " + tokens[i];
Read the first integer. Jump to back of the string and skip digits. Then read an int from this point. The part in the middle is the string. May not be 100% correct but:
char buf[256], *t = buf, *p, str[256];
fread(buf, 1, 256, file);
int s,e;
t += sscanf(buf, "%d", &s);
*p = buf + strlen(buf);
while (isdigit(*p)) p--;
sscanf(p, "%d", &e);
strncpy(str, p, p - t);
This is not as efficient as #KerrekSB's solution, but another way to do this is to extract the first integer, then loop through the rest of the string until you find the second integer.
#include <iostream>
#include <sstream>
int main()
{
std::istringstream ss( "100 4 words to discard 200" );
int first, second;
char buf[1000] = {0};
if( !( ss >> first ) ) {
std::cout << "failed to read first int\n";
return 1;
}
while( !( ss >> second ) || !ss.eof() ) {
if( ss.eof() ) {
std::cout << "failed to read second int\n";
return 1;
}
ss.clear();
if( ss.getline( buf, 1000, ' ' ).bad() ) {
std::cout << "error extracting word\n";
return 1;
}
}
std::cout << "first = " << first << "\n";
std::cout << "second = " << second << "\n";
return 0;
}