c

examples

examples.cšŸ”§
/**
 * String Parsing and Tokenization - Examples
 * 
 * This file demonstrates string parsing techniques in C.
 * 
 * Compile: gcc examples.c -o examples
 * Run: ./examples
 */

#define _POSIX_C_SOURCE 200809L

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>

/* ============================================================
 * EXAMPLE 1: Basic strtok Usage
 * ============================================================ */

void example1_basic_strtok(void) {
    printf("=== EXAMPLE 1: Basic strtok Usage ===\n\n");
    
    char str[] = "apple,banana,cherry,date";
    
    printf("Original string: \"%s\"\n\n", str);
    printf("Tokenizing with ',':\n");
    
    // First call - pass the string
    char *token = strtok(str, ",");
    int count = 0;
    
    while (token != NULL) {
        printf("  Token %d: \"%s\"\n", ++count, token);
        // Subsequent calls - pass NULL
        token = strtok(NULL, ",");
    }
    
    printf("\nNote: Original string was modified:\n");
    printf("  str = \"%s\" (only first token visible)\n", str);
    
    // Show what happened in memory
    printf("\nMemory view (commas replaced with \\0):\n");
    printf("  ");
    char *p = str;
    for (int i = 0; i < 25; i++) {
        if (*p == '\0') {
            printf("[\\0]");
        } else {
            printf("[%c]", *p);
        }
        p++;
    }
    printf("\n");
}


/* ============================================================
 * EXAMPLE 2: Multiple Delimiters
 * ============================================================ */

void example2_multiple_delimiters(void) {
    printf("\n=== EXAMPLE 2: Multiple Delimiters ===\n\n");
    
    char str[] = "Hello,World;How:Are You";
    
    printf("String: \"%s\"\n", str);
    printf("Delimiters: \",;: \" (comma, semicolon, colon, space)\n\n");
    
    char *token = strtok(str, ",;: ");
    int count = 0;
    
    while (token != NULL) {
        printf("  Token %d: \"%s\"\n", ++count, token);
        token = strtok(NULL, ",;: ");
    }
    
    printf("\nTotal: %d tokens\n", count);
}


/* ============================================================
 * EXAMPLE 3: strtok Behavior with Empty Fields
 * ============================================================ */

void example3_empty_fields(void) {
    printf("\n=== EXAMPLE 3: Empty Fields (strtok skips them!) ===\n\n");
    
    char str[] = "one,,two,,,three";
    
    printf("String: \"%s\"\n", str);
    printf("Notice: multiple consecutive commas\n\n");
    
    char *token = strtok(str, ",");
    int count = 0;
    
    printf("Using strtok (skips empty fields):\n");
    while (token != NULL) {
        printf("  Token %d: \"%s\"\n", ++count, token);
        token = strtok(NULL, ",");
    }
    
    printf("\nImportant: strtok treats consecutive delimiters as one!\n");
    printf("If you need empty fields, use a custom tokenizer.\n");
}


/* ============================================================
 * EXAMPLE 4: Thread-Safe strtok_r
 * ============================================================ */

void example4_strtok_r(void) {
    printf("\n=== EXAMPLE 4: Thread-Safe strtok_r ===\n\n");
    
    char str[] = "apple,banana,cherry";
    char *saveptr;  // State is stored here instead of static variable
    
    printf("String: \"%s\"\n\n", str);
    
    char *token = strtok_r(str, ",", &saveptr);
    int count = 0;
    
    while (token != NULL) {
        printf("  Token %d: \"%s\"\n", ++count, token);
        printf("    saveptr points to: \"%s\"\n", 
               saveptr ? saveptr : "(end)");
        token = strtok_r(NULL, ",", &saveptr);
    }
    
    printf("\nstrtok_r is safe for:\n");
    printf("  - Multi-threaded programs\n");
    printf("  - Nested tokenization\n");
}


/* ============================================================
 * EXAMPLE 5: Nested Tokenization with strtok_r
 * ============================================================ */

void example5_nested_tokenization(void) {
    printf("\n=== EXAMPLE 5: Nested Tokenization ===\n\n");
    
    char str[] = "user=john;pass=secret;role=admin";
    
    printf("Parsing: \"%s\"\n", str);
    printf("Format: key=value pairs separated by ;\n\n");
    
    char *outer_saveptr, *inner_saveptr;
    char *pair = strtok_r(str, ";", &outer_saveptr);
    
    while (pair != NULL) {
        printf("Pair: \"%s\"\n", pair);
        
        // Inner tokenization - split on '='
        char *key = strtok_r(pair, "=", &inner_saveptr);
        char *value = strtok_r(NULL, "=", &inner_saveptr);
        
        printf("  Key: \"%s\", Value: \"%s\"\n\n", 
               key, value ? value : "(empty)");
        
        pair = strtok_r(NULL, ";", &outer_saveptr);
    }
}


/* ============================================================
 * EXAMPLE 6: Split into Array Function
 * ============================================================ */

int split_string(char *str, char *tokens[], int max_tokens, 
                 const char *delim) {
    int count = 0;
    char *token = strtok(str, delim);
    
    while (token != NULL && count < max_tokens) {
        tokens[count++] = token;
        token = strtok(NULL, delim);
    }
    
    return count;
}

void example6_split_to_array(void) {
    printf("\n=== EXAMPLE 6: Split String into Array ===\n\n");
    
    char str[] = "apple,banana,cherry,date,elderberry";
    char *tokens[10];
    
    printf("String: \"%s\"\n\n", str);
    
    int count = split_string(str, tokens, 10, ",");
    
    printf("Split into %d tokens:\n", count);
    for (int i = 0; i < count; i++) {
        printf("  tokens[%d] = \"%s\"\n", i, tokens[i]);
    }
}


/* ============================================================
 * EXAMPLE 7: Counting Tokens First
 * ============================================================ */

int count_tokens(const char *str, const char *delim) {
    // Must copy since strtok modifies string
    char *copy = strdup(str);
    if (copy == NULL) return -1;
    
    int count = 0;
    char *token = strtok(copy, delim);
    
    while (token != NULL) {
        count++;
        token = strtok(NULL, delim);
    }
    
    free(copy);
    return count;
}

void example7_count_tokens(void) {
    printf("\n=== EXAMPLE 7: Counting Tokens First ===\n\n");
    
    const char *str = "one,two,three,four,five";
    
    printf("String: \"%s\"\n", str);
    
    int count = count_tokens(str, ",");
    printf("Token count: %d\n\n", count);
    
    // Now we can allocate exact size needed
    printf("Original string is preserved: \"%s\"\n", str);
}


/* ============================================================
 * EXAMPLE 8: Number Parsing with Validation
 * ============================================================ */

// Safe integer parsing with error detection
int parse_int_safe(const char *str, int *result) {
    if (str == NULL || *str == '\0') return 0;
    
    char *endptr;
    errno = 0;
    
    long value = strtol(str, &endptr, 10);
    
    // Check for errors
    if (errno == ERANGE) return 0;      // Overflow/underflow
    if (endptr == str) return 0;         // No digits found
    if (*endptr != '\0') return 0;       // Extra characters
    if (value < INT_MIN || value > INT_MAX) return 0;  // Out of int range
    
    *result = (int)value;
    return 1;
}

// Safe double parsing
int parse_double_safe(const char *str, double *result) {
    if (str == NULL || *str == '\0') return 0;
    
    char *endptr;
    errno = 0;
    
    double value = strtod(str, &endptr);
    
    if (errno == ERANGE) return 0;
    if (endptr == str) return 0;
    if (*endptr != '\0') return 0;
    
    *result = value;
    return 1;
}

void example8_number_parsing(void) {
    printf("\n=== EXAMPLE 8: Safe Number Parsing ===\n\n");
    
    printf("--- Integer Parsing ---\n");
    
    const char *int_tests[] = {"123", "-456", "  42", "12abc", "", "999999999999"};
    int num_tests = sizeof(int_tests) / sizeof(int_tests[0]);
    
    for (int i = 0; i < num_tests; i++) {
        int value;
        if (parse_int_safe(int_tests[i], &value)) {
            printf("  \"%s\" -> %d (success)\n", int_tests[i], value);
        } else {
            printf("  \"%s\" -> FAILED\n", int_tests[i]);
        }
    }
    
    printf("\n--- Double Parsing ---\n");
    
    const char *double_tests[] = {"3.14", "-2.5e10", ".5", "1e-5", "not_a_number"};
    num_tests = sizeof(double_tests) / sizeof(double_tests[0]);
    
    for (int i = 0; i < num_tests; i++) {
        double value;
        if (parse_double_safe(double_tests[i], &value)) {
            printf("  \"%s\" -> %g (success)\n", double_tests[i], value);
        } else {
            printf("  \"%s\" -> FAILED\n", double_tests[i]);
        }
    }
}


/* ============================================================
 * EXAMPLE 9: Parsing Different Number Bases
 * ============================================================ */

void example9_number_bases(void) {
    printf("\n=== EXAMPLE 9: Parsing Different Number Bases ===\n\n");
    
    char *endptr;
    long value;
    
    printf("--- Explicit Base ---\n");
    
    value = strtol("1010", &endptr, 2);    // Binary
    printf("  \"1010\" (base 2) = %ld\n", value);
    
    value = strtol("777", &endptr, 8);     // Octal
    printf("  \"777\" (base 8) = %ld\n", value);
    
    value = strtol("255", &endptr, 10);    // Decimal
    printf("  \"255\" (base 10) = %ld\n", value);
    
    value = strtol("FF", &endptr, 16);     // Hexadecimal
    printf("  \"FF\" (base 16) = %ld\n", value);
    
    printf("\n--- Auto-detect Base (base 0) ---\n");
    
    value = strtol("100", &endptr, 0);     // Decimal (no prefix)
    printf("  \"100\" -> %ld (decimal)\n", value);
    
    value = strtol("0x64", &endptr, 0);    // Hex with 0x prefix
    printf("  \"0x64\" -> %ld (hex)\n", value);
    
    value = strtol("0144", &endptr, 0);    // Octal with 0 prefix
    printf("  \"0144\" -> %ld (octal)\n", value);
}


/* ============================================================
 * EXAMPLE 10: Parsing CSV Data
 * ============================================================ */

typedef struct {
    char name[50];
    int age;
    double salary;
} Employee;

int parse_employee(const char *line, Employee *emp) {
    char buffer[256];
    strncpy(buffer, line, sizeof(buffer) - 1);
    buffer[sizeof(buffer) - 1] = '\0';
    
    char *saveptr;
    
    // Parse name
    char *token = strtok_r(buffer, ",", &saveptr);
    if (token == NULL) return 0;
    strncpy(emp->name, token, sizeof(emp->name) - 1);
    
    // Parse age
    token = strtok_r(NULL, ",", &saveptr);
    if (token == NULL) return 0;
    emp->age = atoi(token);
    
    // Parse salary
    token = strtok_r(NULL, ",", &saveptr);
    if (token == NULL) return 0;
    emp->salary = atof(token);
    
    return 1;
}

void example10_csv_parsing(void) {
    printf("\n=== EXAMPLE 10: Parsing CSV Data ===\n\n");
    
    const char *csv_lines[] = {
        "John Doe,30,50000.50",
        "Jane Smith,25,45000.00",
        "Bob Johnson,35,62500.75"
    };
    
    printf("Parsing employee records:\n\n");
    
    for (int i = 0; i < 3; i++) {
        printf("Line: \"%s\"\n", csv_lines[i]);
        
        Employee emp;
        if (parse_employee(csv_lines[i], &emp)) {
            printf("  Name: %s\n", emp.name);
            printf("  Age: %d\n", emp.age);
            printf("  Salary: $%.2f\n\n", emp.salary);
        } else {
            printf("  Parse error!\n\n");
        }
    }
}


/* ============================================================
 * EXAMPLE 11: Parsing Key-Value Pairs
 * ============================================================ */

typedef struct {
    char key[64];
    char value[128];
} KeyValue;

int parse_key_value(const char *line, KeyValue *kv) {
    // Find '=' separator
    const char *eq = strchr(line, '=');
    if (eq == NULL) return 0;
    
    // Copy key (trim spaces)
    const char *key_start = line;
    while (isspace(*key_start)) key_start++;
    
    const char *key_end = eq - 1;
    while (key_end > key_start && isspace(*key_end)) key_end--;
    
    size_t key_len = key_end - key_start + 1;
    if (key_len >= sizeof(kv->key)) key_len = sizeof(kv->key) - 1;
    strncpy(kv->key, key_start, key_len);
    kv->key[key_len] = '\0';
    
    // Copy value (trim spaces)
    const char *val_start = eq + 1;
    while (isspace(*val_start)) val_start++;
    
    const char *val_end = val_start + strlen(val_start) - 1;
    while (val_end > val_start && isspace(*val_end)) val_end--;
    
    size_t val_len = val_end - val_start + 1;
    if (val_len >= sizeof(kv->value)) val_len = sizeof(kv->value) - 1;
    strncpy(kv->value, val_start, val_len);
    kv->value[val_len] = '\0';
    
    return 1;
}

void example11_key_value_parsing(void) {
    printf("\n=== EXAMPLE 11: Parsing Key-Value Pairs ===\n\n");
    
    const char *lines[] = {
        "host = localhost",
        "port=8080",
        "username = admin",
        "  password  =  secret123  "
    };
    
    for (int i = 0; i < 4; i++) {
        printf("Line: \"%s\"\n", lines[i]);
        
        KeyValue kv;
        if (parse_key_value(lines[i], &kv)) {
            printf("  Key: \"%s\"\n", kv.key);
            printf("  Value: \"%s\"\n\n", kv.value);
        }
    }
}


/* ============================================================
 * EXAMPLE 12: Using sscanf for Pattern Parsing
 * ============================================================ */

void example12_sscanf_patterns(void) {
    printf("\n=== EXAMPLE 12: Using sscanf for Pattern Parsing ===\n\n");
    
    // Parse coordinates
    printf("--- Parsing Coordinates ---\n");
    int x, y;
    if (sscanf("Point(10, 20)", "Point(%d, %d)", &x, &y) == 2) {
        printf("  \"Point(10, 20)\" -> x=%d, y=%d\n", x, y);
    }
    
    // Parse IP address
    printf("\n--- Parsing IP Address ---\n");
    int a, b, c, d;
    if (sscanf("192.168.1.100", "%d.%d.%d.%d", &a, &b, &c, &d) == 4) {
        printf("  \"192.168.1.100\" -> %d.%d.%d.%d\n", a, b, c, d);
    }
    
    // Parse date
    printf("\n--- Parsing Date ---\n");
    int year, month, day;
    if (sscanf("2024-03-15", "%d-%d-%d", &year, &month, &day) == 3) {
        printf("  \"2024-03-15\" -> Year=%d, Month=%d, Day=%d\n", 
               year, month, day);
    }
    
    // Parse with string field
    printf("\n--- Parsing Mixed Data ---\n");
    char name[50];
    int age;
    double score;
    if (sscanf("John,25,95.5", "%[^,],%d,%lf", name, &age, &score) == 3) {
        printf("  \"John,25,95.5\" -> Name=%s, Age=%d, Score=%.1f\n",
               name, age, score);
    }
    
    // Parse time
    printf("\n--- Parsing Time ---\n");
    int hour, min, sec;
    if (sscanf("14:30:45", "%d:%d:%d", &hour, &min, &sec) == 3) {
        printf("  \"14:30:45\" -> %02d:%02d:%02d\n", hour, min, sec);
    }
}


/* ============================================================
 * EXAMPLE 13: Custom Tokenizer (Handles Empty Fields)
 * ============================================================ */

// Tokenizer that doesn't skip empty fields
char *strtok_single(char *str, char delim, char **saveptr) {
    if (str != NULL) {
        *saveptr = str;
    }
    
    if (*saveptr == NULL || **saveptr == '\0') {
        return NULL;
    }
    
    char *token_start = *saveptr;
    
    // Find delimiter or end
    while (**saveptr != delim && **saveptr != '\0') {
        (*saveptr)++;
    }
    
    if (**saveptr == delim) {
        **saveptr = '\0';
        (*saveptr)++;
    }
    
    return token_start;
}

void example13_custom_tokenizer(void) {
    printf("\n=== EXAMPLE 13: Custom Tokenizer (Empty Fields) ===\n\n");
    
    char str[] = "one,,three,,,six";
    
    printf("String: \"%s\"\n", str);
    printf("Note: multiple consecutive commas\n\n");
    
    char *saveptr;
    char *token = strtok_single(str, ',', &saveptr);
    int count = 0;
    
    printf("Custom tokenizer (preserves empty fields):\n");
    while (token != NULL) {
        if (*token == '\0') {
            printf("  Token %d: (empty)\n", count);
        } else {
            printf("  Token %d: \"%s\"\n", count, token);
        }
        count++;
        token = strtok_single(NULL, ',', &saveptr);
    }
    
    printf("\nTotal: %d tokens (including empty ones)\n", count);
}


/* ============================================================
 * EXAMPLE 14: Complete Config File Parser
 * ============================================================ */

typedef struct {
    char host[64];
    int port;
    char username[32];
    char password[64];
    int debug;
} Config;

void init_config_defaults(Config *cfg) {
    strcpy(cfg->host, "localhost");
    cfg->port = 8080;
    cfg->username[0] = '\0';
    cfg->password[0] = '\0';
    cfg->debug = 0;
}

int parse_config_line(const char *line, Config *cfg) {
    // Skip empty lines and comments
    const char *p = line;
    while (isspace(*p)) p++;
    if (*p == '\0' || *p == '#') return 1;  // OK, just skip
    
    KeyValue kv;
    if (!parse_key_value(line, &kv)) {
        return 0;
    }
    
    if (strcmp(kv.key, "host") == 0) {
        strncpy(cfg->host, kv.value, sizeof(cfg->host) - 1);
    } else if (strcmp(kv.key, "port") == 0) {
        cfg->port = atoi(kv.value);
    } else if (strcmp(kv.key, "username") == 0) {
        strncpy(cfg->username, kv.value, sizeof(cfg->username) - 1);
    } else if (strcmp(kv.key, "password") == 0) {
        strncpy(cfg->password, kv.value, sizeof(cfg->password) - 1);
    } else if (strcmp(kv.key, "debug") == 0) {
        cfg->debug = (strcmp(kv.value, "true") == 0 || 
                     strcmp(kv.value, "1") == 0);
    }
    
    return 1;
}

void example14_config_parser(void) {
    printf("\n=== EXAMPLE 14: Config File Parser ===\n\n");
    
    const char *config_content = 
        "# Server configuration\n"
        "host = 192.168.1.50\n"
        "port = 3000\n"
        "\n"
        "# Authentication\n"
        "username = admin\n"
        "password = secret123\n"
        "\n"
        "debug = true\n";
    
    printf("Config content:\n%s\n", config_content);
    
    Config cfg;
    init_config_defaults(&cfg);
    
    // Parse line by line
    char *content = strdup(config_content);
    char *saveptr;
    char *line = strtok_r(content, "\n", &saveptr);
    
    while (line != NULL) {
        parse_config_line(line, &cfg);
        line = strtok_r(NULL, "\n", &saveptr);
    }
    
    free(content);
    
    printf("Parsed configuration:\n");
    printf("  host:     %s\n", cfg.host);
    printf("  port:     %d\n", cfg.port);
    printf("  username: %s\n", cfg.username);
    printf("  password: %s\n", cfg.password);
    printf("  debug:    %s\n", cfg.debug ? "true" : "false");
}


/* ============================================================
 * MAIN FUNCTION
 * ============================================================ */

int main(void) {
    printf("╔═══════════════════════════════════════════════════════╗\n");
    printf("ā•‘    STRING PARSING AND TOKENIZATION - EXAMPLES         ā•‘\n");
    printf("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n\n");
    
    example1_basic_strtok();
    example2_multiple_delimiters();
    example3_empty_fields();
    example4_strtok_r();
    example5_nested_tokenization();
    example6_split_to_array();
    example7_count_tokens();
    example8_number_parsing();
    example9_number_bases();
    example10_csv_parsing();
    example11_key_value_parsing();
    example12_sscanf_patterns();
    example13_custom_tokenizer();
    example14_config_parser();
    
    printf("\n╔═══════════════════════════════════════════════════════╗\n");
    printf("ā•‘              ALL EXAMPLES COMPLETED!                  ā•‘\n");
    printf("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n");
    
    return 0;
}
Examples - C Programming Tutorial | DeepML