C ++ gets hour and minutes from a string

I am writing C ++ code for a school in which I can only use the std library, so no enhancement. I need to parse a string like "14:30" and parse it into:

unsigned char hour; unsigned char min; 

We get the string as a C ++ string, so there is no direct pointer. I tried all variations of this code:

 sscanf(hour.c_str(), "%hhd[:]%hhd", &hours, &mins); 

but I keep getting the wrong data. What am I doing wrong.

+4
source share
6 answers

Like everyone else, you must use the specified format %d (or %u ). Regarding alternative approaches, I am not a big fan of "because C ++ has a XX function that you need to use" and often resort to level C functions. Although I have never used scanf() -like material because it had its problems . Here is how I can parse your string using strtol() with error checking:

 #include <cstdio> #include <cstdlib> int main() { unsigned char hour; unsigned char min; const char data[] = "12:30"; char *ep; hour = (unsigned char)strtol(data, &ep, 10); if (!ep || *ep != ':') { fprintf(stderr, "cannot parse hour: '%s' - wrong format\n", data); return EXIT_FAILURE; } min = (unsigned char)strtol(ep+1, &ep, 10); if (!ep || *ep != '\0') { fprintf(stderr, "cannot parse minutes: '%s' - wrong format\n", data); return EXIT_FAILURE; } printf("Hours: %u, Minutes: %u\n", hour, min); } 

Hope this helps.

+1
source

Your problem, of course, is that you are using sscanf . And that you use a special type for hours and minutes, instead of of int . Since you are parsing a string of exactly 5 characters, the simplest solution is simply to make sure that all characters are legal in this position using isdigit for characters 0, 1, 3 and 4 and compared to ':' for character 2. Once you have this done, it is trivial to create std::istringstream from a string and input to int , a char (which you will ignore later) and a second int . If you want to be more flexible in input, for example, allowing things like "9:45" , for example, you can skip the initial checks and just type in int , char and int , then check that char contains ':' (and that there are two int are in range).

As for your sscanf tag: you are asking it to match something like "12[:]34" , which is not what you give it. I'm not sure if you are trying to use "%hhd:%hhd" , or if for some reason you really need a character class, in which case you should use [ as a conversion specifier, and then ignore the input: "%hhd%*[:]%hhd" . (This would allow taking more than one character as a separator, but for the rest I see no advantage. In addition, technically, at least using %d and then passing the address of unsigned integral types is not supported, %hhd should be signed char . In practice, however, I do not think that you will ever have problems for non-negative input values ​​less than 128.)

+2
source

As izomorphius sscanf was mentioned, and the options are not C ++, they are C. The C ++ way is to use streams. The following works (this is not surprisingly flexible, but should give you an idea)

 #include <iostream> #include <string> #include <sstream> using namespace std; int main(int argc, char* argv[]) { string str = "14:30"; stringstream sstrm; int hour,min; sstrm << str; sstrm >> hour; sstrm.get(); // get colon sstrm >> min; cout << hour << endl; cout << min << endl; return 0; } 

You can also use getline to get everything to the colon.

+1
source

I would do it like this:

 unsigned tmp_hour, tmp_mins; unsigned char hour, mins; sscanf(hour.c_str(), "%u:%u", &tmp_hours, &tmp_mins); hour = tmp_hours; mins = tmp_mins; 

Less mess with obscure scanf options. I would also add error checking.

+1
source

I understand that h in %hhd not a valid format specifier. The correct qualifier for decimal integers is %d .

As R. Martinho Fernandez says in his comment, %d:%d will correspond to two numbers separated by a colon (':').

Do you need something else?

You can always read the entire text string and parse it in any way.

0
source

sscanf with %hhd:%hhd works fine:

 std::string time("14:30"); unsigned char hour, min; sscanf(time.c_str(), "%hhd:%hhd", &hour, &min); 

Note that the hh length modifier simply allows you to store the value in an unsigned char.

However, sscanf is from the C standard library, and there are more efficient C ++ methods for this. For this, C ++ 11 uses stoi :

 std::string time("14:30"); unsigned char hour = std::stoi(time); unsigned char min = std::stoi(time.substr(3)); 

In C ++ 03, we can use stringstream , but it hurts a little if you really want it in char :

 std::stringstream stream("14:30"); unsigned int hour, min; stream >> hour; stream.ignore(); stream >> min; 
0
source

Source: https://habr.com/ru/post/1447001/


All Articles