Hello
I need the user to input for example a time format HH:MM(AMorPM) or a complex number format: X+jY

Then I want to read HH in and int and MM in another int
and the same for the complex number example.

I am aware I should use delimiters, but i dont know what to do, any help will be appreciated

Dani AI

Generated

Short answer for the original question: formatted extraction (e.g. cin >> hh) reads an integer token and stops as soon as the token ends — that is, when a non-digit is reached (the : in 10:40). So cin >> hh will happily parse 2329 from 2329:40; it does not “know” the intended field width, so you must validate the value (0–12, 0–59, etc.) after extraction. (en.cppreference.com)

For interactive console input the usual pattern is: read a whole line with std::getline and then parse that string. That avoids the “partial input / waiting for more characters” problem described by and lets you reject a malformed line atomically. After you have the line you can (a) use std::istringstream (as suggested earlier), (b) split on delimiters, or (c) scan manually. std::getline reads until the newline and discards it, so it’s the right tool for line-oriented prompts. (en.cppreference.com)

If you want a modern, fast, robust parser, consider scanning the string with std::from_chars (C++17) for the integer pieces and test the characters between pieces. Example sketch:

// uses <charconv>, <string>, <cctype>
bool parse_time(const std::string& s, int& hh, int& mm, std::string& ampm) {
    const char* p = s.c_str();
    const char* end = p + s.size();
    auto r = std::from_chars(p, end, hh);
    if (r.ec != std::errc() || r.ptr == p) return false;
    p = r.ptr;
    if (p==end || *p != ':') return false; ++p;
    r = std::from_chars(p, end, mm);
    if (r.ec != std::errc() || r.ptr == p) return false;
    p = r.ptr;
    while (p < end && std::isspace((unsigned char)*p)) ++p;
    ampm.assign(p, end); // then normalize/check "AM"/"PM"
    return hh>=1 && hh<=12 && mm>=0 && mm<60 && (ampm=="AM"||ampm=="PM");
}

std::from_chars is non-throwing and locale-independent — a good fit for this use case. (en.cppreference.com)

For complex numbers (e.g. X+jY) parse similarly: trim, detect and strip the trailing j/i, find the separator sign between real and imaginary (careful with leading sign on the real part), then parse the two numeric substrings. If you need floating parsing and maximum portability, std::stod is simple; std::from_chars supports floating conversions in the standard but floating-point from_chars has had uneven library support across implementations — check your standard library / compiler version before relying on it. (stackoverflow.com)

Practical tips: always validate ranges after parsing, use cin.ignore() or prefer getline to avoid leftover newline problems, and reject the whole line on a format error rather than trying to recover mid-stream. This keeps the UI predictable for users.

Recommended Answers

All 21 Replies

Look at the time input validation stuff and try to adopt it for complex number input (and other user types):

struct Time {
    int hh, mm;
    std::string ampm; // "AM" or "PM"
};

bool getTime(std::istream& is, Time& t)
{
    bool res = false;
    char c;
    if (is >> t.hh) { // true if it's a number
        if (is.get(c) && c == ':' && (is >> t.mm)) { // :MM here
            if ((is >> t.ampm) && (t.ampm == "AM" || t.ampm == "PM")) {
                // Check up hh & mm values
                if (t.hh >= 0 && t.hh <= 12 && t.mm >= 0 && t.mm < 60)
                    res = true; // good time value
            }
        }
    } 
    return res;
}
// Advanced (syntax sugar):
std::istream& operator>>(std::istream& is, Time& t) {
    if (!getTime(is,t))
        is.setstate(std::ios::failbit);
    return is;
}
std::ostream& operator<<(std::ostream& os, const Time& t) {
    os << t.hh << ':' << t.mm << ' ' << t.ampm;
    return os;
}

However this approach has a serious defect in the console input environment. If the user types a part of a valid time value only then getTime waits the rest of Time value. It seems like you program hangs. Possible workaround: read a line then use istringstream:

bool GetTime(Time& t)
{
    bool res = false;
    std::string line;
    if (std::getline(std::cin,line)) {
        std::istringstream is(line);
        res = getTime(is,t);
    }
    return res;
}

Of course, it's not a reference implementation. Sorry but I have no time to prepare Program Logic Manual for this improvisation ;)...

I had that first method in a book.

But i have a question:
how does the program know how many characters are hh and mm and so on

we fist tell it if(cin>>hh) will that work whether the user inputs 10:40 or 2329:40?

I will check for it to be between 0 and 12, but the thing I mean is how can it tell that it will stop before the ":"

Member Avatar for Member #46692

Another option would be to use boost libraries and regex to evaluate a correct time. It would save a lot of messing around as ArkM has demonstrated. :P

For example:

Another option would be to use boost libraries and regex to evaluate a correct time. It would save a lot of messing around as ArkM has demonstrated. :P

For example:

I am not doing it for the time, I want to learn the method, the time is just an example.

Would appreciate if someone tell me what tells the program to stop reading hh before the delimiter when i use

if (cin>>hh>

Member Avatar for Member #46692

Nah look at the link below kiddo:
http://www.daniweb.com/forums/post140537-2.html

Then you separate them into to arrays.

array[0]
array[1]

Then go through all the rules, so you ensure you get valid times.

Nah look at the link below kiddo:
http://www.daniweb.com/forums/post140537-2.html

okay, this is alot easier, but this will get all of them as strings, i want to be able to extract some as strings, some as chars and some as intergers and doubles
and i also want them to be into different variables, not just one, like token for example

and is the std:: instead of using namespace std ??

okay, i dont get the last part you added to your post, about the arrays, how can i extract different types as I specified, and keep them in different variables

Member Avatar for Member #46692

Pretty simple really, to convert a string to an int etc, just use stringstreams.

http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1046996179&id=1043284385

You don't really need to use single chars here.


And if you use a vector instead of an array you just build the values on the fly as you go. Although you could use a dynamic array, but that's gay in my opinion.

okay, and what you meant by the arrays

you mean instead of the while with the token,

i make it like getlink(iss, token, :) ????

is that what you mean?
btw, i never used stringstreams, and i dont even know what is iss :)

Member Avatar for Member #46692

>btw, i never used stringstreams, and i dont even know what is iss

Yeah well, you learn something new tous le jour and such and such.

yes, i agree, but you didnt answer my question about the arrays

Member Avatar for Member #46692

Well personally I'd use a vector:

vissssssssssssssssssss

#include <iostream>
#include <vector>
#include <string>
#include <sstream>

using namespace std;

int main()
{

   vector <string> array; 
 
   string tmp = "12:20";
   string token;
   istringstream iss(tmp);
   while ( getline(iss, token, ':') )
   {
      array.push_back(token);
   }   
   cout <<array[0] <<endl;
   cout <<array[1] <<endl;
   
   cin.get();
}

i think i will have to

vector<int> array


in order for that to work, correct?

Member Avatar for Member #46692

I guess, but I'm just conjecturing here.

I was thinking you might get into trouble with times such as "03:45" but maybe stringstream converts the "03" to 3 anyhoo.

Don't quote me on that.

very good,

but i am not quite getting istringstream, i got its to input the stream, and does iss has anything to do with it?

Member Avatar for Member #46692

Post your code...

what code?
I mean the one you made, this one:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>

using namespace std;

int main()
{

   vector <string> array; 
 
   string tmp = "12:20";
   string token;
   istringstream iss(tmp);
   while ( getline(iss, token, ':') )
   {
      array.push_back(token);
   }   
   cout <<array[0] <<endl;
   cout <<array[1] <<endl;
   
   cin.get();
}
Member Avatar for Member #46692

Is that a joke? No the bit where you're not quite getting the istringstream?

Post an example of what you've tried, state what you expect, and what you're unsure of.

by "I am not getting istringstream"

I mean i dont understand it, and i dont know what it does.

>how does the program know how many characters are hh and mm and so on
>we fist tell it if(cin>>hh) will that work whether the user inputs 10:40 or 2329:40?
>I will check for it to be between 0 and 12, but the thing I mean is how can it tell that it will stop before the ":"
The overloaded operator>>(istream&,int&) stops to extract characters from a stream when integer representation ended. Obviously, the colon is not a part of integer. That's all. The next get(char&) extracts stop-char and we can compare it with desired colon char.
We will check hours and minutes after input operations ended (see line #14 in my snippet above):

line #14:
if (t.hh >= 0 && t.hh <= 12 && t.mm >= 0 && t.mm < 60)

>by "I am not getting istringstream" ... I mean i dont understand it, and i dont know what it does.
http://www.deitel.com/articles/cplusplus_tutorials/20060211/index.html
Well, pay attention to getTime; no stringstreams in this (working ;)) function.

You asked a general question about input data validation. Be ready to get general answers ;)...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.