Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <stddef.h>
- #define ELEMENTS(x) (sizeof x/sizeof *x)
- #define TENS(x) (((char) x - '0') * 10)
- #define UNITS(x) ((char) x - '0')
- #define ID_FOUND_MARK 255
- /* The pattern string tell us what elements on the array units should we mark.
- *
- * The comma separator are used to mark single units, the dash separator are used
- * for 'ranges' with the former number being the lower bound of the range and
- * the latter number being the upper bound of the range.
- *
- * Numbers found on the pattern string will be marked with the 255 number.
- *
- * Assumptions made:
- * - The former number on the range is smaller then the former number.
- * - There is no spaces on the string.
- * - There is no ranges with double dash, e.g. 1-5-7.
- * - All numbers are 1 or 2 digits.
- */
- void parse_units(const char *pattern, uint8_t *units, const size_t units_size)
- {
- const size_t pattern_len = strlen(pattern);
- char *parser_cursor = NULL;
- size_t parser_cursor_pos = 0;
- size_t parser_step = 1;
- printf("\r\nPattern %s\r\n\r\n", pattern);
- // Begin the parsing
- for (parser_cursor = pattern; parser_cursor_pos < pattern_len; parser_cursor += parser_step) {
- bool is_comma_separator = false;
- bool is_dash_separator = false;
- bool is_last_number = false;
- // Does the parser_cursor points to a digit character?
- if (isdigit(*parser_cursor)) {
- char *next_comma = NULL;
- char *next_dash = NULL;
- // Found the closest separator (comma, dash o NULL):
- next_comma = strchr(parser_cursor, ',');
- next_dash = strchr(parser_cursor, '-');
- if ((NULL != next_comma) && (NULL != next_dash)) {
- if (next_comma < next_dash) {
- is_comma_separator = true;
- } else {
- is_dash_separator = true;
- }
- } else if ((NULL == next_comma) && (NULL != next_dash)) {
- is_dash_separator = true;
- } else if ((NULL != next_comma) && (NULL == next_dash)) {
- is_comma_separator = true;
- } else {
- // No more comas nor dashes, so we reached
- // the last number on the pattern
- is_last_number = true;
- }
- if (is_comma_separator) {
- uint8_t num = 0;
- ptrdiff_t num_digits = 0;
- num_digits = next_comma - parser_cursor;
- if (num_digits == 1) {
- num = UNITS(*parser_cursor);
- } else if (num_digits == 2) {
- num = TENS(*parser_cursor) + UNITS(*(parser_cursor + 1));
- }
- printf("number found: %d\r\n", num);
- // Mark the number found
- if (num < units_size) {
- units[num] = ID_FOUND_MARK;
- }
- // this will place the cursor right after the comma
- parser_step = (size_t) num_digits + 1;
- } else if (is_dash_separator) {
- // If a dash is being found then we need to parse the first
- // and second numbers.
- printf("Range found\r\n");
- uint8_t first_number = 0;
- ptrdiff_t first_num_digits = 0;
- ptrdiff_t second_num_digits = 0;
- uint8_t second_num = 0;
- char *second_comma = NULL;
- char *next_separator = NULL;
- // first number
- first_num_digits = next_dash - parser_cursor;
- if (first_num_digits == 1) {
- first_number = UNITS(*parser_cursor);
- } else if (first_num_digits == 2) {
- first_number = TENS(*parser_cursor) + UNITS(*(parser_cursor + 1));
- }
- printf("\tfirst_number: %d\r\n", first_number);
- // Move the parser_cursor after the dash separator
- parser_cursor = next_dash + 1;
- parser_cursor_pos += (size_t) first_num_digits + 1;
- // ASSUMPTION:
- // When we found a dash separator the next separator can only be:
- // - comma
- // - NULL (end of the pattern string)
- second_comma = strchr(parser_cursor, ',');
- next_separator = pattern + strlen(pattern);
- // If a comma was found then next_separator will point to it.
- if (second_comma != NULL) {
- next_separator = second_comma;
- }
- second_num_digits = next_separator - parser_cursor;
- if (second_num_digits == 1) {
- second_num = UNITS(*parser_cursor);
- } else if (second_num_digits == 2) {
- second_num = TENS(*parser_cursor) + UNITS(*(parser_cursor + 1));
- }
- printf("\tsecond_number: %d\r\n", second_num);
- // Mark the numbers found
- // TODO:
- // If the second_num is bigger than units_size should we
- // truncate marking the numbers up to the last element of the
- // units array?
- if (first_number < units_size || second_num < units_size) {
- for (size_t idx = first_number; idx <= second_num; idx++) {
- units[idx] = ID_FOUND_MARK;
- }
- }
- // this will place the cursor right after the comma
- parser_step = (size_t) second_num_digits + 1;
- } else if (is_last_number) {
- size_t num_size = 0;
- uint8_t num = 0;
- // Get the amount of the remaining digits
- num_size = strlen(parser_cursor);
- if (num_size == 1) {
- num = UNITS(*parser_cursor);
- } else if (num_size == 2) {
- num = TENS(*parser_cursor) + UNITS(*(parser_cursor + 1));
- }
- printf("last number: %d\r\n", num);
- // Mark the number found
- if (num < units_size) {
- units[num] = ID_FOUND_MARK;
- }
- parser_step = num_size;
- }
- } else {
- // The parser cursor was not pointing to a number character so we
- // just move the pointer to the next character.
- parser_step = 1;
- }
- // Keep the parser_cursor_pos up to date
- parser_cursor_pos += parser_step;
- }
- printf("parsing done\r\n");
- }
- int main(void)
- {
- uint8_t objects[40] = {0};
- parse_units("1-3,4,5,6,8,9,10,12-14", objects, ELEMENTS(objects));
- memset(objects, 0, ELEMENTS(objects));
- parse_units("4-10,26", objects, ELEMENTS(objects));
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement