Home > Enterprise >  Best way to parse and handle adjoining data (like hhmmss)?
Best way to parse and handle adjoining data (like hhmmss)?

Time:06-05

For example i have a string about time like 134058 (hhmmss). What is the best way to parse and handle this data? I think i can do this with strncmp or some loops but i am not sure if it's the logical or efficant way.

And what kind of data type should i keep these variable with?

CodePudding user response:

There are some functions in stdlib.h, atoi and strtol, which can not be used here.

Therefore, sticking with the answers from the comments is best.

#include <stdio.h>
#include <string.h> // for strlen
#include <ctype.h> // for isdigit

enum {TIME_LENGTH = 6};

int main(void) {
    int hours, minutes, seconds;
    char *input_string = "134058";

    if (strlen(input_string) != TIME_LENGTH) {
        return 1; // wrong length
    }

    for (int i = 0; i < TIME_LENGTH; i  ) {
        if (input_string[i] < '0' || input_string[i] > '9') {
            return 1; // element not a digit
        }
    }

    // just for completeness, seems like an overkill here
    for (int i = 0; i < TIME_LENGTH; i  ) {
        if (!isdigit(input_string[i])) {
            return 1; // element not a digit
        }
    }

    // straight way, drop '* 1' if used
    hours =   (input_string[0] - '0') * 10   (input_string[1] - '0') * 1;
    minutes = (input_string[2] - '0') * 10   (input_string[3] - '0') * 1;
    seconds = (input_string[4] - '0') * 10   (input_string[5] - '0') * 1;
    printf("Time: d:d:d\n", hours, minutes, seconds);

    // from chux - Reinstate Monica
    sscanf(input_string, "---", &hours, &minutes, &seconds);
    printf("Time: d:d:d\n", hours, minutes, seconds);

    // from Support Ukraine
    hours =   10 * input_string[0]   input_string[1] - 11 * '0';
    minutes = 10 * input_string[2]   input_string[3] - 11 * '0';
    seconds = 10 * input_string[4]   input_string[5] - 11 * '0';
    printf("Time: d:d:d\n", hours, minutes, seconds);

    return 0;
}
$ gcc -Wall parse_simple_time_string.c
$ ./a.out                             
Time: 13:40:58
Time: 13:40:58
Time: 13:40:58
$ 

CodePudding user response:

Depends what you mean by 'best'. Some examples shown already , they will also suit your needs. I prefer generic reusable methods; though of course the choice is up to you depending on how much you will re-use the code.

The following code allows range checking, and invalid string checking , haven't tested fully but once you've written the function once it can be re-used to suit. Any comments welcome.

#include <stdint.h>
#include <stdbool.h>

/**
 * @param str string to parse
 * @param len length of string to parse
 * @param out value pointer
 * @param min minimum allowed value
 * @param max maximum allowed value
 * @return true if parsed correctly, false if parse error
 * @description convert part of a string to decimal number between specified range
 * @example
 * uint32_t hour;
 * // function returns true and sets hour value to 12
 * parseDecimalInt("12345",2,&hour,0,23);
 */
bool parseDecimalInt(const char* str, int32_t len, int32_t* out, int32_t min, int32_t max)
{
    int32_t base = 1;
    // convert string to len
    *out = 0;

    if (strlen(str) < len) // check string is longer than desired string to parse
        return false;

    if (len < 1)
        return false; // invalid string length

    len--;

    while (len >= 0)
    {
        int8_t digit = str[len] - '0';

        if (digit < 0 || digit > 9)
            return false; // invalid number

        *out = *out   (base * digit);
        base *= 10;
        len--;
    }

    // outside bounds checks
    if (*out < min)
        return false;
    if (*out > max)
        return false;

    return true;
}

void main()
{
    int32_t hours, mins, secs;
    const char* str = "123456";
    // Parses TWO characters as decimal starting from ZEROTH character in string
    if (!parseDecimalInt(&str[0], 2, &hours, 0, 23))
    {
        // error parsing hours - print something here and return
    }
    // Parses TWO characters as decimal starting from SECOND character in string
    if (!parseDecimalInt(&str[2], 2, &mins, 0, 59))
    {
        // error parsing mins - print something here and return 
    }
    // Parse TWO characters as decimal starting from FOURTH character in string
    if (!parseDecimalInt(&str[4], 2, &secs, 0, 59))
    {
        // error parsing seconds - print something here and return 
    }
    // if returned on error, hours mins, secs should be valid
    // hours will be 12, mins will be 34, secs will be 56
}
  • Related