If I have a string (from user) of "{1, 2, 3, 4, 5}", how would I convert that to a vector of {1, 2, 3, 4, 5} in C ?
I tried to get a string from the user by
vector<int> input;
cin >> input;
but I got error:
./main.cpp:124:9: error: invalid operands to binary expression ('std::istream' (aka 'basic_istream<char>') and 'vector<int>')
cin >> user_input;
CodePudding user response:
A suggestion: convert your string into an input stream.
Try something like this:
const std::string input_data="{1, 2, 3, 4, 5}";
std::istringstream input_stream(input_data);
char c; // Used for ignoring characters.
std::vector<int> database;
int number;
// Ignore the first brace
input_stream >> c;
// Read in the first number
input_stream >> number;
database.push_back(number);
// Read in the separator;
input_stream >> c;
// Read in the next number
input_stream >> number;
database.push_back(number);
// ...
The test for the ending brace or end of input are left as an exercise for the OP. :-)
CodePudding user response:
I have this utility function I use to stream in specific characters like { and }
template<class e, class t>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e& cliteral) {
e buffer; //get buffer
in >> buffer; //read data
if (buffer != cliteral) //if it failed
in.setstate(in.rdstate() | std::ios::failbit); //set the state
return in;
}
And with that, you can use an istream_iterator to stream the ints that the user types directly into the vector:
std::cin >> '{';
std::vector<int> input(std::istream_iterator<int>(std::cin), {});
std::cin >> '}';
CodePudding user response:
So, this is where a library of useful functions comes in. I keep quite a few.
First, we’ll need something to range over a container (such as a string):
#include <utility>
template <typename Iterator>
struct ranger : public std::pair <Iterator, Iterator>
{
ranger( Iterator begin, Iterator end = Iterator() ) : std::pair <Iterator, Iterator> { begin, end } { }
Iterator begin() { return this->first; }
Iterator end () { return this->second; }
};
Next we’ll want something to make iterating over a string with regular expressions easier:
#include <regex>
#include <string>
struct re_ranger : public std::regex, public ranger <std::sregex_iterator>
{
template <typename RegEx>
re_ranger( const RegEx& re, const std::string& s )
: std::regex( re )
, ranger( std::sregex_iterator( s.begin(), s.end(), *this ) )
{ }
};
And we will naturally want to have the ability to turn a string like "7" into an integer like 7:
#include <optional>
#include <sstream>
#include <string>
template <typename T>
auto string_to( const std::string & s )
{
T value;
std::istringstream ss( s );
return ((ss >> value) and (ss >> std::ws).eof())
? value
: std::optional<T> { };
}
This makes selecting and converting the numbers in a string to a vector of integers stupidly simple:
#include <iostream>
#include <vector>
int main()
{
std::string input = "{1, 2, 3, 4, 5}";
std::vector<int> xs;
for (auto m : re_ranger( "[[:digit:]] ", input ))
xs.emplace_back( *string_to<int>(m.str()) );
Since we are converting one way, we might as well be able to convert the other way. Here’s the freebie:
#include <sstream>
#include <string>
template <typename Iterator>
std::string join( Iterator begin, Iterator end, const std::string & separator = " " )
{
std::ostringstream ss;
if (begin != end)
{
ss << *begin ;
while (begin != end)
ss << separator << *begin ;
}
return ss.str();
}
template <typename Container>
std::string join( const Container & xs, const std::string & separator = " " )
{
using std::begin;
using std::end;
return join( begin( xs ), end( xs ), separator );
}
Now we can finish off main():
#include <iostream>
#include <numeric>
#include <vector>
int main()
{
std::string input = "{1, 2, 3, 4, 5}";
std::vector<int> xs;
for (auto s : re_ranger( "[[:digit:]] ", input ))
xs.emplace_back( *string_to<int>( s.str() ) );
std::cout << join( xs, " " )
<< " = " << std::accumulate( xs.begin(), xs.end(), 0 ) << "\n";
}
Output:
1 2 3 4 5 = 15
PS. You should get user input as a string:
int main()
{
std::string input;
std::cout << "input? ";
getline( std::cin, input );
CodePudding user response:
Here is another way of parsing the input. It uses a helper type to expect a specific character in the input stream (and eat it).
#include <cctype>
#include <iostream>
struct expect
{
char c;
explicit expect( char c ) : c{c} { }
};
std::istream & operator >> ( std::istream & ins, const expect & c )
{
if (!std::isspace( (unsigned char)c.c )) ins >> std::ws;
if (ins.peek() == c.c) ins.get();
else ins.setstate( std::ios::failbit );
return ins;
}
Now we can write our input function. I’ll overload >> for a vector of integers:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::istream & operator >> ( std::istream & ins, std::vector<int> & xs )
{
int x;
xs.clear();
if (!(ins >> expect( '{' ))) return ins;
while (ins >> x)
{
xs.emplace_back( x );
ins >> expect( ',' );
}
ins.clear();
ins >> expect( '}' );
return ins;
}
Notice how the function works: it expects specific input. If that input fails at any given time the stream will be set to a fail state and the function will return. Now we can use it much like I think you had planned in your question:
int main()
{
std::string input = "{1, 2, 3, 4, 5}";
std::vector<int> xs;
std::istringstream ss( input );
ss >> xs;
for (int x : xs)
std::cout << x << " ";
std::cout << "\n";
}
Helper functions for the win!
PS. There is a companion function/class named accept which does nearly the same thing as expect. It just doesn’t set the fail state if the desired character is not next in the input stream.
struct accept
{
char c;
explicit accept( char c ) : c{c} { }
};
std::istream & operator >> ( std::istream & ins, const accept & c )
{
if (!std::isspace( (unsigned char)c.c )) ins >> std::ws;
if (ins.peek() == c.c) ins.get();
return ins;
}
These two functions are the basis for a lot of very useful parsing powers.
