Cin help

how do i take input that contains other characters. for example, if i wanted to take in a point such as (12,4). How do i get cin to only read the numbers?
Something along these lines, perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct point { int x = 0 ; int y = 0 ; };

std::ostream& operator<< ( std::ostream& stm, point pt )
{ return stm << '(' << pt.x << ',' << pt.y << ')' ; }

std::istream& operator>> ( std::istream& stm, point& pt )
{
    char left_paren, comma, right_paren ;
    int x, y ;

    if( stm >> left_paren >> x >> comma >> y >> right_paren && 
        left_paren == '(' && comma == ',' && right_paren == ')' ) { pt = { x, y } ; }

    else { pt = {} ; stm.clear(stm.failbit) ; } // bad input: zero pt, put stream into a failed state

    return stm ;
}

http://coliru.stacked-crooked.com/a/ea37e6d14380700f
http://rextester.com/SDDK3600
Last edited on
Good question!
Alas, getting input correctly is a difficult task.

Here's an example of how to correctly get a point from stream.
(And just so you know, this is not the only correct way to do it!)

The salient point is: if an invalid character is encountered, it is not extracted and the stream is left in fail() state. Otherwise everything is A-OK.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>

//-----------------------------------------------------------------------------
// The point class
template <typename T>
struct point
{
  T x;
  T y;
  point(): x(), y() { }
  point( const T& x, const T& y ): x(x), y(y) { }
};

//-----------------------------------------------------------------------------
// Stream insertion operator (output a point)
template <typename T>
std::ostream& operator << ( std::ostream& outs, const point <T> & p )
{
  return outs << "(" << p.x << "," << p.y << ")";
}

//-----------------------------------------------------------------------------
// Helper type to only extract a character if it is the next available in the
// input stream.
struct match
{
  char c;
  match( char c ): c(c) { }
};

//-----------------------------------------------------------------------------
// Extract the "match" character IFF it matches.
// Otherwise, leave the stream in fail().
std::istream& operator >> ( std::istream& ins, const match& e )
{
  ins >> std::ws;
  if (ins.peek() == e.c) ins.get();
  else ins.setstate( ins.rdstate() | std::ios::failbit );
  return ins;
}

//-----------------------------------------------------------------------------
// Stream extraction operator (input a point)
// The point MUST be formatted properly or input fails with fail().
template <typename T>
std::istream& operator >> ( std::istream& ins, point <T> & p )
{
  std::istream::sentry sentry( ins, true );
  if (!sentry)
  {
    ins.setstate( ins.rdstate() | std::ios::failbit );
    return ins;
  }
  
  return ins >> match( '(' ) >> p.x >> match( ',' ) >> p.y >> match( ')' );
}

//-----------------------------------------------------------------------------
// Testing
#include <sstream>
#include <string>

int main()
{
  point <int> p;
  
  std::cout << "Try inputting some integer points. Press ENTER when done.\n";
  
  while (true)
  {
    // Prompt the user and get everything entered
    std::cout << "> ";
    std::string s;
    std::getline( std::cin, s );
    
    // Empty lines mean "all done"
    if (s.empty()) break;
    
    // Extract as many points as possible from the line and display them
    std::istringstream ss( s );
    while (ss >> p)
      std::cout << "point " << p << "\n";
      
    // If something went wrong, display the unprocessed part of the input
    if (!ss.eof())
    {
      ss.clear();
      std::getline( ss, s );
      std::cout << "fooey! Remaining string = \"" << s << "\"\n";
    }
  }
}

Feel free to cut and paste (and modify, if your point structure is different) this code for your own use.

In particular, my "point" type is templated. If yours is not, you must delete all the lines that say "template" and replace the "T"s with your type and remove all the "<T>"s.

Hope this helps.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template< typename T > struct point // T : an arithmetic type for which std::complex<T> is supported
{
    T x;
    T y;
    point( T x = {}, T y = {} ) : x(x), y(y) {}
};

template < typename T, typename OSTREAM > OSTREAM& operator<< ( OSTREAM& stm, point<T> pt ) 
{ return stm << std::complex<T>( pt.x, pt.y ) ; } // format: (x,y)

// read pt from an input stream. supported formats are: x, (x) and (x,y). 
template < typename T, typename ISTREAM > ISTREAM& operator>> ( ISTREAM& stm, point<T>& pt ) 
{ 
    std::complex<T> c ; 
    if( stm >> c ) pt = { c.real(), c.imag() } ; 
    else pt = {} ;
    return stm ; 
} 

http://coliru.stacked-crooked.com/a/0b3b358d37a7fb14
I don't like that solution. It co-opts std::complex<> to represent something it wasn't meant to represent, and consequently accepts invalid points for input. ("12" and "(12)" do not represent a valid 2D point.)

Personally, I don't like represent complex numbers as a tuple either. Use the standard notation: "2+3i". This is a whole other can of beans, though.
Hmm, good point. I think we jumped the gun on the "must be a point" kind of response.

To only extract numbers, eliminate everything that isn't a number:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <algorithm>
#include <cctype>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
  cout << "Enter strings with numbers in them. Press ENTER to quit.\n";
  while (true)
  {
    string s;
    cout << "> ";
    getline( cin, s );
    if (s.empty()) break;
    
    transform( s.begin(), s.end(), s.begin(), []( char c ) -> char
    {
      return isdigit(c) ? c : ' ';
    } );
    istringstream ss( s );
    int n;
    while (ss >> n)
      cout << "number: " << n << "\n";
  }
}

Maybe?
Last edited on
> To only extract numbers, eliminate everything that isn't a number

This is hard:
For instance, from "+1.23e-2e+-12.e-3.5e", we must extract 0.0123, -0.012 and 0.5
This can be parsed, and quite easily parsed at that.
It is taking care of all possible edge cases that is hard.

A brute force solution:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>

int main()
{
    std::string input = "+1.23e-2e+-12.e-3.5e" ;

    while( !input.empty() )
    {
        try
        {
            std::size_t pos = 0 ;
            std::cout << std::stod( input, std::addressof(pos) ) << '\n' ;
            input = input.substr(pos) ;
        }
        catch( const std::exception& ) { input = input.substr(1) ; }
    }
}

http://coliru.stacked-crooked.com/a/40e6cd008c9f9daa
My teacher told us to use the cin.ingnore() function. But I'm not sure if that only works if it's only the number first and then different characters.
> use the cin.ingnore() function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct point { point( int x = 0, int y = 0 ) : x(x), y(y) {} int x ; int y ; };

std::ostream& operator<< ( std::ostream& stm, point pt )
{ return stm << '(' << pt.x << ',' << pt.y << ')' ; }

std::istream& operator>> ( std::istream& stm, point& pt )
{
    int x, y ;
    
    if( stm.ignore( 1000, '(' ) && // extract and discard characters till a '(' has been extracted and discarded
        stm >> x && // read an integer into x
        stm.ignore( 1000, ',' ) && // extract and discard characters till a ',' has been extracted and discarded
        stm >> y && // read an integer into y
        stm.ignore( 1000, ')' ) && // extract and discard characters till a ')' has been extracted and discarded
        !stm.eof() // eof was not reached before the ')' was extracted
      ) 
    { 
        pt = { x, y } ; // success, update pt with x, y
    }

    else { pt = {} ; stm.clear(stm.failbit) ; } // input failed: clear pt, and put stream into a failed state

    return stm ;
}

http://coliru.stacked-crooked.com/a/f82ac39963765acb
Is this @gentleguy going to keep spamming? You just posted 3 meaningless posts in the span of 18 minutes. Seriously?
I am in school i cant reply quickly. But the assignment is to find the midpoint between two points and i am just stuck on the cin part.
this is what i am going to start with instead of using the cin.ignore()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#include <iostream>

using namespace std;

int main(){

float point1,point2;

cout << "Enter the points"<<endl;

cin >> point1>>point2;

cout << point1<< "," <<point2<<endl;



return 0;
}


It looks like you have a good start. I expect your professor to want you to use 2D points:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

int main()
{
  float p1x, p1y;  // point 1 has x,y components
  float p2x, p2y;  // point 2 likewise

  cout << "Enter point 1 x and y: ";
  cin >> p1x >> p1y;

  cout << "Enter point 2 x and y: ";
  cin >> p2x >> p2y;

  float mx, my;  // midpoint has x,y components
  // You need to do the math here to figure out mx and my using p1x,p1y and p2x,p2y

  cout << "The points         " << p1x << "," << p1y << "\n"
       << "and                " << p2x << "," << p2y << "\n"
       << "have a midpoint of " << mx  << "," << my << ".\n";
}

Good luck!
I suspect that OP has input given in a specific format which a simple cin >> a >> b; cannot handle. Until he gives us more information we can only guess.
I figured it out and made it like duoas.
Topic archived. No new replies allowed.