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 int
s 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.