#c #string #scanf
#c #строка #scanf
Вопрос:
Мне нужно извлечь значение для данного ключа из строки. Я сделал эту быструю попытку:
char js[] = "some preceding text withn"
"new lines and spacesn"
"param_1=123n"
"param_2=321n"
"param_3=stringn"
"param_2=321n";
char* param_name = "param_2";
char *key_s, *val_s;
char buf[32];
key_s = strstr(js, param_name);
if (key_s == NULL)
return 0;
val_s = strchr(key_s, '=');
if (val_s == NULL)
return 0;
sscanf(val_s 1, "1s", buf);
printf("'%s'n", buf);
И это на самом деле работает нормально ( printf
выдает '321'
). Но я полагаю scanf
, что / sscanf
сделает эту задачу еще проще, но мне не удалось определить строку форматирования для этого.
Возможно ли передать содержимое переменной param_name
, sscanf
чтобы она оценивала его как часть строки форматирования? Другими словами, мне нужно указать sscanf
, что в этом случае он должен искать шаблон param_2=%s
( param_name
фактически он исходит из аргумента функции).
Комментарии:
1. Я думаю, ваш
sscanf
вызов копирует слишком много, если значение не является последней записью, может быть, вы хотите"1[^n]"
?2. @mafso, %s остановится при попадании на белый символ (который равен n)
3. Конечно. Извините за глупый комментарий.
4. Обратите внимание, что это «работает», потому что у вас нет
param_22=xyz
записи (илиspare_param_2=abc
записи) передparam_2=321
записью.5. Вероятно, вам лучше всего использовать библиотеку регулярных выражений или какой-либо другой анализатор. Хотя
scanf
и допускает поведение регулярных выражений, определяемое реализацией, полагаться на это хрупко.
Ответ №1:
Не напрямую, нет.
На практике, конечно, ничто не мешает вам создавать строку формата для sscanf()
во время выполнения, например snprintf()
.
Что-то вроде:
void print_value(const char **js, size_t num_js, const char *key)
{
char tmp[32], value[32];
snprintf(tmp, sizeof tmp, "%s=%1s", key);
for(size_t i = 0; i < num_js; i)
{
if(sscanf(js[i], tmp, value) == 1)
{
printf("found '%s'n", value);
break;
}
}
}
Ответ №2:
У OP есть хороший первый шаг:
char *key_s = strstr(js, param_name);
if (key_s == NULL)
return 0;
Остальное может быть упрощено до
if (sscanf(amp;key_s[strlen(param_name)], "=1s", buf) == 0) {
return 0;
}
printf("'%s'n", buf);
В качестве альтернативы можно было бы использовать " =1s"
, чтобы разрешить пробелы раньше =
.
Подход OP вводит в заблуждение "param_2 321n" "param_3=stringn"
.
Примечание: слабость всех ответов до сих пор заключается в том, чтобы не анализировать пустую строку.
Ответ №3:
Одна из проблем, которая заслуживает рассмотрения, заключается в разнице между поиском параметра «ключ = значение» в строке для определенного значения ключа (например, param_2
в вопросе) и поиском любого параметра «ключ = значение» в строке (без учета конкретного ключа априори).). Используемые методы довольно разные.
Еще одна проблема, которая, очевидно, не рассматривалась, — это возможность того, что вы ищете ключ param_2
, но строка также содержит param_22=xyz
и t_param_2=abc
. Простые подходы, используемые strstr()
для поиска param_2
, подберут любую из этих альтернатив.
В образце данных имеется набор символов, которые не находятся в формате ‘ключ = значение’, которые должны быть пропущены перед любыми частями ‘ключ = значение’. В общем случае мы должны предположить, что такие данные появляются до, между и после пар «ключ = значение». Похоже, что значения не должны поддерживать такие сложности, как строки в кавычках и метасимволы, а значение разделено пробелом. Соглашение о комментариях не отображается.
Вот несколько работоспособных кодов:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAX_KEY_LEN = 31 };
enum { MAX_VAL_LEN = 63 };
int find_any_key_value(const char *str, char *key, char *value);
int find_key_value(const char *str, const char *key, char *value);
int find_any_key_value(const char *str, char *key, char *value)
{
char junk[256];
const char *search = str;
while (*search != '')
{
int offset;
if (sscanf(search, " 1[a-zA-Z_0-9]=cs%n", key, value, amp;offset) == 2)
return(search offset - str);
int rc;
if ((rc = sscanf(search, "%5s%n", junk, amp;offset)) != 1)
return EOF;
search = offset;
}
return EOF;
}
int find_key_value(const char *str, const char *key, char *value)
{
char found[MAX_KEY_LEN 1];
int offset;
const char *search = str;
while ((offset = find_any_key_value(search, found, value)) > 0)
{
if (strcmp(found, key) == 0)
return(search offset - str);
search = offset;
}
return offset;
}
int main(void)
{
char js[] = "some preceding text withn"
"new lines and spacesn"
"param_1=123n"
"param_2=321n"
"param_3=stringn"
"param_4=param_2=confusionn"
"m= xn"
"param_2=987n";
const char p2_key[] = "param_2";
int offset;
const char *str;
char key[MAX_KEY_LEN 1];
char value[MAX_VAL_LEN 1];
printf("String being scanned is:n[[%s]]n", js);
str = js;
while ((offset = find_any_key_value(str, key, value)) > 0)
{
printf("Any found key = [%s] value = [%s]n", key, value);
str = offset;
}
str = js;
while ((offset = find_key_value(str, p2_key, value)) > 0)
{
printf("Found key %s with value = [%s]n", p2_key, value);
str = offset;
}
return 0;
}
Пример вывода:
$ ./so24490410
String being scanned is:
[[some preceding text with
new lines and spaces
param_1=123
param_2=321
param_3=string
param_4=param_2=confusion
m= x
param_2=987
]]
Any found key = [param_1] value = [123]
Any found key = [param_2] value = [321]
Any found key = [param_3] value = [string]
Any found key = [param_4] value = [param_2=confusion]
Any found key = [m] value = [x]
Any found key = [param_2] value = [987]
Found key param_2 with value = [321]
Found key param_2 with value = [987]
$
Если вам нужно обрабатывать разные длины ключей или значений, вам необходимо настроить строки формата, а также перечисления. Если вы передаете размер ключевого буфера и размер буфера значений функциям, то вам нужно использовать snprint()
для создания строк формата, используемых sscanf()
. Существует вероятность того, что у вас может быть одно «слово» из 255 символов, за которым сразу следует целевая строка «ключ = значение». Шансы смехотворно малы, но вы можете решить, что вам нужно беспокоиться об этом (это предотвращает защиту этого кода от бомб).