c
examples
examples.cš§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;
}