我有一个文件,其中某些字段由制表符分隔。一行中总是会有12个标签,某些标签是连续的,表示一个空字段。我想使用fscanf将连续的选项卡读取为空字段并将其存储在结构中。但是似乎有一个问题。这是我的文件:
usrid User Id 0 15 string d k y y 0 0
当我尝试使用fscanf进行读取时,制表符之间的制表符不能识别为空字段,并且数据存储在错误的结构字段中。解决问题的最佳方法是什么?
答案 0 :(得分:3)
fscanf
不是入门者。读取空字段的唯一方法是使用"%c"
读取定界符(这将要求您事先知道哪些字段为空-不太有用),否则,取决于 format说明符使用em>时,fscanf
会简单地将tabs
用作前导空白或遇到匹配失败或输入失败。
从注释继续,为了基于可能分隔空字段的分隔符进行标记化,您将需要使用strsep
,因为strtok
会将连续的分隔符视为一个。
虽然您的字符串不太清楚tabs
的位置,但是使用strsep
标记的简短示例如下。请注意,strsep
将指针指向指针的第一个参数,例如
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
int n = 0;
const char *delim = "\t\n";
char *s = strdup ("usrid\tUser Id 0\t15\tstring\td\tk\ty\ty\t\t\t0\t0"),
*toks = s, /* tokenize with separate pointer to preserve s */
*p;
while ((p = strsep (&toks, delim)))
printf ("token[%2d]: '%s'\n", n++ + 1, p);
free (s);
}
(注意:,由于strsep
将修改字符串指针所保存的地址,因此您需要保留指向s
开头的指针,以便在出现以下情况时可以将其释放不再需要-感谢JL)
使用/输出示例
$ ./bin/strtok_tab
token[ 1]: 'usrid'
token[ 2]: 'User Id 0'
token[ 3]: '15'
token[ 4]: 'string'
token[ 5]: 'd'
token[ 6]: 'k'
token[ 7]: 'y'
token[ 8]: 'y'
token[ 9]: ''
token[10]: ''
token[11]: '0'
token[12]: '0'
仔细检查一下,如果还有其他问题,请告诉我。
答案 1 :(得分:0)
我想使用fscanf将连续的选项卡读取为空字段并将其存储在结构中。
理想情况下,代码应该像fgets()
一样读取行,然后解析 string 。
还留在fscanf()
上,可以循环执行。
主要思想是使用"%[^/t/n]"
读取一个令牌。如果下一个字符是'\t'
,则返回值将不是1。为此进行测试。宽度限制是明智的。
然后阅读分隔符并查找制表符,行尾或是否发生文件结束/错误。
#define TABS_PER_LINE 12
#define TOKENS_PER_LINE (TABS_PER_LINE + 1)
#define TOKEN_SIZE 100
#define TOKEN_FMT_N "99"
int fread_tab_delimited_line(FILE *istream, int n, char token[n][TOKEN_SIZE]) {
for (int i = 0; i < n; i++) {
int token_count = fscanf(istream, "%" TOKEN_FMT_N "[^\t\n]", token[i]);
if (token_count != 1) {
token[i][0] = '\0'; // Empty token
}
char separator;
int term_count = fscanf(istream, "%c", &separator); // fgetc() makes more sense here
// if end-of-file or end-of-line
if (term_count != 1 || separator == '\n') {
if (i == 0 && token_count != 1 && term_count != 1) {
return 0;
}
return i + 1;
}
if (separator != '\t') {
return -1; // Token too long
}
}
return -1; // Token too many tokens found
}
示例驾驶代码
void test_tab_delimited_line(FILE *istream) {
char token[TOKENS_PER_LINE][TOKEN_SIZE];
long long line_count = 0;
int token_count;
while ((token_count = fread_tab_delimited_line(istream, TOKENS_PER_LINE, token)) > 0) {
printf("Line %lld\n", ++line_count);
for (int i = 0; i < token_count; i++) {
printf("%d: <%s>\n", i, token[i]);
}
} while (token_count > 0);
if (token_count < 0) {
puts("Trouble reading any tokens.");
}
}