Спецификаторы формата строки sscanf не работают для '\t'

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
char *tokenstring = "first,25.5,second,15";
int result, i;
double fp;
char o[10], f[10], s[10], t[10];
void main()
{
   result = sscanf(tokenstring, "%[^','],%[^','],%[^','],%s", o, s, t, f);
   printf("%s\n %s\n %s\n %s\n", o, s, t, f);
   fp = atof(s);
   i  = atoi(f);
   printf("%s\n %lf\n %s\n %d\n", o, fp, t, i);
}

Коды выше не работает для '\t', почему? Это работает для этого я использую vc6.0

Не работает

char *tokenstring = "first\t25.5\tsecond\t15";



   result = sscanf(tokenstring, "%[^'\t'],%[^'\t'],%[^'\t'],%s", o, s, t, f);

2 ответа

Решение

Посмотрите, что ваш формат соответствует:

"%[^'\t'],%[^'\t']
 ^     ^ ^
 \     | \- match a literal comma
  \    |
   \---+- match a sequence not containing tab or ' (single quote), up to the next
          tab or single quite.

Итак, первый %[..] сопоставляет все до и не включая первую вкладку во входных данных, а затем пытается сопоставить запятую, которая не соответствует вкладке и, таким образом, завершается ошибкой.

Самый простой способ - заменить запятые в строке пробелами, которые пропустят пробелы (включая вкладки). Использование вкладок сделает то же самое, но заставит людей думать, что вы пытаетесь сопоставить вкладку, а не пропускать пробелы:

sscanf(tokenstring, "%[^\t] %[^\t] %[^\t]%s", o, s, t, f);

Обратите внимание, что вы также, вероятно, не хотите лечить ' символы специально в матчах, если вы не хотите, чтобы они потерпели неудачу.

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

sscanf(tokenstring, "%[^\t]%*1[\t\]%[^\t]%*1[\t]%[^\t]%s", o, s, t, f);

Шаблон %*1[\t] будет точно соответствовать одной вкладке на входе и нигде не будет храниться.

Это приводит к другой проблеме, которую вы, возможно, заметили при первом сканировании (на основе запятых) - %[^,] или же %[^\t] не будет соответствовать пустой строке - если следующий символ на входе , (или же \t во втором случае), scanf будет просто возвращать, не сопоставляя ничего (или любой из следующих шаблонов), вместо того, чтобы хранить пустую строку.

Кроме того, если какая-либо из ваших строк слишком длинна для массивов, вы переполнитесь и вылетите (или хуже). Поэтому всякий раз, когда вы используете scanf %s или же %[ шаблон в буфер, вы должны ВСЕГДА указывать размер буфера:

sscanf(tokenstring, "%9[^,],%9[^,],%9[^,],%9s", o, s, t, f);

Теперь вместо того, чтобы разбивать или портить вещи, когда ввод слишком длинный, sscanf call будет соответствовать только первым 9 символам поля и будет возвращаться с остальной частью поля, которую еще предстоит прочитать.

Когда вы используете запятую для разделения полей, вам нужно будет добавить , к строке формата, чтобы пропустить ее. Аналогично для \t,

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

void test1()
{
   char *tokenstring = "first,25.5,second,15";
   int result, i;
   double fp;
   char o[10], f[10], s[10], t[10];

   // -----------------------------------------------------------
   // make sure you add a , between the string format specifiers
   // -----------------------------------------------------------
   result = sscanf(tokenstring, "%[^,],%[^,],%[^,],%s", o, s, t, f);
   printf("%s\n %s\n %s\n %s\n", o, s, t, f);
   fp = atof(s);
   i  = atoi(f);
   printf("%s\n %lf\n %s\n %d\n", o, fp, t, i);
}

void test2()
{
   char *tokenstring = "first\t25.5\tsecond\t15";
   int result, i;
   double fp;
   char o[10], f[10], s[10], t[10];

   // -----------------------------------------------------------
   // make sure you add a \t between the string format specifiers
   // -----------------------------------------------------------
   result = sscanf(tokenstring, "%[^\t]\t%[^\t]\t%[^\t]\t%s", o, s, t, f);
   printf("%s\n %s\n %s\n %s\n", o, s, t, f);
   fp = atof(s);
   i  = atoi(f);
   printf("%s\n %lf\n %s\n %d\n", o, fp, t, i);
}

void main()
{
   test1();
   test2();
}
Другие вопросы по тегам