Если существует только фиксированный набор ключей, которые вас когда-либо интересуют, то вам также нужна таблица, которая связывает ключи с соответствующими переменными. Как пример:
enum { Key1, Key2, Key3 /* ... */};
struct {
const char *key;
int value;
} key_table[KEY_TABLE_SZ] = {
[Key1] = { "Key1", INT_MIN },
[Key2] = { "Key2", INT_MIN },
[Key3] = { "Key3", INT_MIN },
/* ... */
};
Когда вы анализируете строку параметров запроса и идентифицируете ключи, вы можете выполнить поиск в таблице, чтобы установить значение в связанной переменной.
const char *key;
const char *value;
char *query_string2 = strdup(query_string);
char *rest = query_string2;
while ((rest = parse_query_string(rest, &key, &value)) != NULL) {
int i = key_table_find(key);
if (i == -1) {
/* ... unknown key ... */
continue;
}
key_table[i].value = strtol(value, 0, 10);
}
free(query_string2);
Тогда интересующее вас значение может быть проиндексировано перечислением.
if (key_table[Key1] != INT_MIN) {
/* ... do something with Key1 ... */
}
Анализ строки параметра может быть выполнен с помощью вызова strchr
и strchrnul
. (Если в вашей системе отсутствует strchrnul
, это похоже на strchr
, за исключением того, что искомый символ не найден, он возвращает указатель на '\0'
в конце строки вместо NULL
.)
char * parse_query_string(char *rest, const char **key, const char **value) {
char *p, *q;
if ((p = rest) == NULL || (q = strchr(p, '=')) == NULL) return NULL;
*q++ = '\0';
if (*(rest = strchrnul(q, '&'))) *rest++ = '\0';
*key = p;
*value = q;
return rest;
}
Обратите внимание, что значения перечисления могут быть инициализированы соответствующими значениями хеш-функции для ускорения операции поиска.
enum {
Key1 = KEY_TABLE_HASH('K', 'e', 'y', '1'),
Key2 = KEY_TABLE_HASH('K', 'e', 'y', '2'),
Key3 = KEY_TABLE_HASH('K', 'e', 'y', '3'),
/* ... */
};
Ниже приведена гипотетическая реализация хэша. Он может обрабатывать только строки длиной до 5 байт, но он должен быть относительно простым, чтобы расширять его до более длинных строк (до максимального уровня вложенности макросов, поддерживаемого в вашей системе).
#define HASH(...) HASH_(UP_TO_5(__VA_ARGS__), __VA_ARGS__)
#define HASH_(...) HASH__(__VA_ARGS__)
#define HASH__(N, ...) HASH_##N(2166136261U, __VA_ARGS__)
#define HASH_5(H, A, ...) HASH_4(HASH_1(H, A), __VA_ARGS__)
#define HASH_4(H, A, ...) HASH_3(HASH_1(H, A), __VA_ARGS__)
#define HASH_3(H, A, ...) HASH_2(HASH_1(H, A), __VA_ARGS__)
#define HASH_2(H, A, ...) HASH_1(HASH_1(H, A), __VA_ARGS__)
#define HASH_1(H, A) (((H) ^ (unsigned)(A)) * 16777619U)
#define UP_TO_5(...) UP_TO_5_(__VA_ARGS__, 5, 4, 3, 2, 1)
#define UP_TO_5_(_1, _2, _3, _4, _5, X, ...) X
#define KEY_TABLE_HASH(...) HASH(__VA_ARGS__) % KEY_TABLE_SZ
enum { KEY_TABLE_SZ = 11 };
И функция поиска реализована с использованием того же алгоритма хеширования.
int key_table_find(const char *key) {
unsigned hash = 2166136261U;
const char *p = key;
while (*p) {
hash = HASH_1(hash, *p);
++p;
}
hash %= KEY_TABLE_SZ;
if (key_table[hash].key == 0) return -1;
if (strcmp(key_table[hash].key, key) != 0) return -1;
return hash;
}
Попробуйте онлайн!