Спецификаторы формата строки 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();
}