2011-12-29 2 views
4

В моей программе я использую sscanf, чтобы проверить, является ли строка заданного формата. Для этого я предоставляю количество аргументов в строке формата и проверяю, возвращает ли этот номер sscanf при анализе ввода.sscanf - переменное количество аргументов формата?

Как часть примитивного анализатора, я хочу проверить, соответствует ли строка одному из форматов. Функция sscanf является вариативной, так как я могу иметь дело с переменным числом аргументов, которые мне нужно передать?

В настоящее время я передаю очень большое количество аргументов (например, 50) функции и надеюсь, что строки формата не содержат больше аргументов.

Есть ли лучший способ сделать это?

+0

regex может быть полезно. – Hogan

+0

@ Хоган: регулярные выражения Afaik не являются частью стандартной библиотеки C. – ryyst

+1

@ryyst Они не являются стандартными c, но они POSIX – Dave

ответ

3

Вам действительно нужно что-то более тяжелое, чем scanf. У вас должно быть сообщитьscanf в каком формате ваш вход; он ничего не может понять сам по себе.

Если у вас есть доступ к POSIX, посмотрите на regex.h, это, вероятно, все, что вам нужно.

В противном случае вы застреваете самостоятельно. lex и yacc хороши, если формат довольно сложный, но в противном случае либо strtok, либо (getchar + switch), вероятно, путь.

Edit: Так как вы можете использовать POSIX, вот простой пример того, как извлекать данные из регулярных выражений в с. (Проверка ошибок исключены для краткости.)

char txt[] = "232343341235898dfsfgs/.f"; 
regex_t reg; 
regmatch_t refs[MAX_REFS]; //as in, the maximum number of data you want to extract 
regcomp(&reg, "3433\\([0-5]*\\).*", 0); //replace 0 with REG_EXTENDED if desired 
regexec(&reg, txt, MAX_REFS, refs, 0); 
regfree(&reg); 

txt[refs[0].rm_eo+1] = '\0'; 
int n = atoi(txt+refs[0].rm_so); 
printf("%d\n", n); 

Печать

41235 
+0

У меня есть доступ к POSIX, поэтому 'regex.h' будет моим следующим выбором. Могу ли я проанализировать ввод в разные переменные с помощью 'regex.h', например' sscanf', или мне придется использовать 'regex.h' и' sscanf'? – ryyst

+0

все, что вам нужно, это 'regexec'. Я добавлю пример – Dave

0

Возможно, вы используете lex/yacc для создания правильного анализатора. В качестве альтернативы, первая токенизация строки с помощью strtok может упростить вашу проблему. (Осторожно: очень правильно использовать strtok - внимательно прочитайте его документацию.)

0

Я не уверен, что это отвечает на ваш вопрос, но you use varargs in C, чтобы переменное число аргументов функции.

void myscanf(const char *fmt, ...) 
{ 
} 
0

беспомощный ответ «не делает этого, написать парсер правильно, может быть, с помощью lex и/или yacc или bison».

Ответ на заданный вами вопрос: «Да, вы могли бы это сделать». Я не верю, что есть какая-то причина, по которой не может быть более вариационных параметров, чем требуется для формата, хотя для немногих было бы плохо. Я предполагаю, что у вас есть массив или список возможных форматов, и вы вызываете sscanf в цикле.

0

Вы можете написать функцию проверки, используя аргументы переменной длины, используя макросы, доступные в stdarg.h.

Например,

int my_validation_func(const char *format, ...) { 
    va_list ap; 
    char *p, *sval; 
    int ival; 
    float fval; 

    va_start(ap, format); 
    for(p=format; *p ; p++) { 
     if (*p != '%') { 
      continue; 
     } 
     switch(*++p) { 
      case 'd': 
       ival = va_arg(ap, int); 
       break; 

      case 'f': 
       fval = va_arg(ap, float); 
       break; 

      case 's': 
       for (sval = va_arg(ap, char *); *sval; sval++); 
       break; 

      default: 
       break; 
     } 
    } 
    va_end(ap); 
} 

Надеется, что это помогает!

0

Если вы не знаете , когда вы пишете код, количество и тип (и) аргументов, sscanf() не могут безопасно делать то, что вы пытаетесь сделать.

Передача 50 аргументов в sscanf() в порядке (аргументы, не потребляемые строкой формата, оцениваются, но игнорируются), но аргументы, соответствующие строке формата, должны быть ожидаемого типа после продвижения; в противном случае поведение не определено. Поэтому, если вы хотите определить, можно ли сканировать строку с помощью "%d" или "%f", вы не можете безопасно сделать это с помощью одного вызова sscanf(). (Вполне вероятно, вы могли бы уйти с пропусканием void*, что указывает на достаточно большой буфер, но поведение все еще не определено.)

Другая неприятная проблема с sscanf() является то, что он не обрабатывает цифровой переполнения. Это:

char *s = "9999999999999999999999999"; 
int n; 
int result = sscanf(s, "%d", &n); 
printf("result = %d, n = %d\n", result, n); 

имеет неопределенное поведение (при условии, 9999999999999999999999999 слишком большой, чтобы хранить в int).

Что-то вы могут быть в состоянии сделать, это найти открытый исходный код sscanf реализации и изменить его так, он просто проверяет строку с форматом, без сохранения ничего. (Работа с лицензией для реализации оставлена ​​как упражнение.) Это имеет смысл, если вы найдете строки стиля sscanf, особенно удобные для вашей проблемы. В противном случае регулярные выражения, вероятно, подходят (не в стандарте C, но достаточно легко найти реализацию).

Смежные вопросы