SHARE
TWEET

parse pattern string

a guest Nov 10th, 2018 16 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <ctype.h>
  4. #include <stdint.h>
  5. #include <stdbool.h>
  6. #include <stddef.h>
  7.  
  8. #define TENS(x)  (((char) x - 0x30) * 10)
  9. #define UNITS(x) ((char) x - 0x30)
  10.  
  11. #define ID_FOUND_MARK 255
  12.  
  13. /* The pattern string tell us what elements on the array units should we mark.
  14.  *
  15.  * The comma separator are used to mark single units, the dash separator are used
  16.  * for 'ranges' with the former number being the lower bound of the range and
  17.  * the latter number being the upper bound of the range.
  18.  *
  19.  * Numbers found on the pattern string will be marked with the 255 number.
  20.  *
  21.  * Assumptions made:
  22.  * - The former number on the range is smaller then the former number.
  23.  * - There is no spaces on the string.
  24.  * - There is no ranges with double dash, e.g. 1-5-7.
  25.  * - All numbers are 1 or 2 digits.
  26.  */
  27. void parse_units(char *pattern, uint8_t *units, size_t units_size)
  28. {
  29.     char *parser_cursor = NULL;
  30.     size_t parser_cursor_pos = 0;
  31.     size_t parser_step = 1;
  32.  
  33.     printf("\r\nPattern %s\r\n\r\n", pattern);
  34.  
  35.     // Begin the parsing
  36.     for (parser_cursor = pattern; parser_cursor_pos < strlen(pattern); parser_cursor += parser_step) {
  37.  
  38.         bool is_comma_separator = false;
  39.         bool is_dash_separator = false;
  40.         bool is_last_number = false;
  41.  
  42.         // Does the parser_cursor points to a digit character?
  43.         if (isdigit(*parser_cursor)) {
  44.             char *next_comma = NULL;
  45.             char *next_dash = NULL;
  46.  
  47.             // Found the closest separator (comma, dash o NULL):
  48.             next_comma = strchr(parser_cursor, ',');
  49.             next_dash = strchr(parser_cursor, '-');
  50.  
  51.             if ((NULL != next_comma) && (NULL != next_dash)) {
  52.                 if (next_comma < next_dash) {
  53.                     is_comma_separator = true;
  54.                 } else {
  55.                     is_dash_separator = true;
  56.                 }
  57.             } else if ((NULL == next_comma) && (NULL != next_dash)) {
  58.                 is_dash_separator = true;
  59.             } else if ((NULL != next_comma) && (NULL == next_dash)) {
  60.                 is_comma_separator = true;
  61.             } else {
  62.                 // No more comas nor dashes, so we reached
  63.                 // the last number on the pattern
  64.                 is_last_number = true;
  65.             }
  66.  
  67.             if (is_comma_separator) {
  68.                 uint8_t num = 0;
  69.                 ptrdiff_t num_digits = 0;
  70.  
  71.                 num_digits = next_comma - parser_cursor;
  72.  
  73.                 if (num_digits == 1) {
  74.                     num = UNITS(*parser_cursor);
  75.                 } else if (num_digits == 2) {
  76.                     num = TENS(*parser_cursor) + UNITS(*(parser_cursor + 1));
  77.                 }
  78.  
  79.                 printf("number found: %d\r\n", num);
  80.  
  81.                 // Mark the number found
  82.                 if (num < units_size) {
  83.                     units[num] = ID_FOUND_MARK;
  84.                 }
  85.                 // this will place the cursor right after the comma
  86.                 parser_step = (size_t) num_digits + 1;
  87.  
  88.             } else if (is_dash_separator) {
  89.                 // If a dash is being found then we need to parse the first
  90.                 // and second numbers.
  91.                 printf("Range found\r\n");
  92.  
  93.                 uint8_t first_number = 0;
  94.                 ptrdiff_t first_num_digits = 0;
  95.  
  96.                 ptrdiff_t second_num_digits = 0;
  97.                 uint8_t second_num = 0;
  98.                 char *second_comma = NULL;
  99.                 char *next_separator = NULL;
  100.  
  101.                 // first number
  102.                 first_num_digits = next_dash - parser_cursor;
  103.  
  104.                 if (first_num_digits == 1) {
  105.                     first_number = UNITS(*parser_cursor);
  106.                 } else if (first_num_digits == 2) {
  107.                     first_number = TENS(*parser_cursor) + UNITS(*(parser_cursor + 1));
  108.                 }
  109.  
  110.                 printf("\tfirst_number: %d\r\n", first_number);
  111.  
  112.                 // Move the parser_cursor after the dash separator
  113.                 parser_cursor = next_dash + 1;
  114.                 parser_cursor_pos += (size_t) first_num_digits + 1;
  115.  
  116.                 // ASSUMPTION:
  117.                 // When we found a dash separator the next separator can only be:
  118.                 // - comma
  119.                 // - NULL (end of the pattern string)
  120.                 second_comma = strchr(parser_cursor, ',');
  121.                 next_separator = pattern + strlen(pattern);
  122.  
  123.                 // If a comma was found then next_separator will point to it.
  124.                 if (second_comma != NULL) {
  125.                     next_separator = second_comma;
  126.                 }
  127.  
  128.                 second_num_digits = next_separator - parser_cursor;
  129.  
  130.                 if (second_num_digits == 1) {
  131.                     second_num = UNITS(*parser_cursor);
  132.                 } else if (second_num_digits == 2) {
  133.                     second_num = TENS(*parser_cursor) + UNITS(*(parser_cursor + 1));
  134.                 }
  135.  
  136.                 printf("\tsecond_number: %d\r\n", second_num);
  137.  
  138.                 // Mark the numbers found
  139.                 // TODO:
  140.                 // If the second_num is bigger than units_size should we
  141.                 // truncate marking the numbers up to the last element of the
  142.                 // units array?
  143.                 if (first_number < units_size || second_num < units_size) {
  144.                     for (size_t idx = first_number; idx <= second_num; idx++) {
  145.                         units[idx] = ID_FOUND_MARK;
  146.                     }
  147.                 }
  148.  
  149.                 // this will place the cursor right after the comma
  150.                 parser_step = (size_t) second_num_digits + 1;
  151.             } else if (is_last_number) {
  152.                 size_t num_size = 0;
  153.                 uint8_t num = 0;
  154.  
  155.                 // Get the amount of the remaining digits
  156.                 num_size = strlen(parser_cursor);
  157.  
  158.                 if (num_size == 1) {
  159.                     num = UNITS(*parser_cursor);
  160.                 } else if (num_size == 2) {
  161.                     num = TENS(*parser_cursor) + UNITS(*(parser_cursor + 1));
  162.                 }
  163.  
  164.                 printf("last number: %d\r\n", num);
  165.  
  166.                 // Mark the number found
  167.                 if (num < units_size) {
  168.                     units[num] = ID_FOUND_MARK;
  169.                 }
  170.                 parser_step = num_size;
  171.             }
  172.  
  173.         } else {
  174.             // The parser cursor was not pointing to a number character so we
  175.             // just move the pointer to the next character.
  176.             parser_step = 1;
  177.         }
  178.  
  179.         // Keep the parser_cursor_pos up to date
  180.         parser_cursor_pos += parser_step;
  181.     }
  182.  
  183.     printf("parsing done\r\n");
  184. }
  185.  
  186. int main(void)
  187. {
  188.     uint8_t objects[40] = {0};
  189.     parse_units("1-3,4,5,6,8,9,10,12-14", objects, sizeof(objects));
  190.     memset(objects, 0, sizeof(objects));
  191.     parse_units("4-10,26", objects, sizeof(objects));
  192.  
  193.     return 0;
  194. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top