我得到了一个分配,该分配使用C读取给定文件并将数据输入到二进制树中。我当前的问题是将从文件中读取的行拆分为两个不同的变量。
已给出的文件包含两位数据,一个ID和一些信息。 2409, blah, blah, blah
当前,程序正在正确读取文件并存储每一行,然后显示它。我尝试使用令牌的,记忆式的,并尝试简单地手动选择字符,但这必须是动态的。 ID不是固定数量的数字,因此手动选择它将不起作用。如前所述,我尝试使用strtok使用“,”作为分隔符,但是它什么都没有改变。
这是当前用于显示信息的内容,我打算在while循环中为每一行拆分字符串:
int main() {
struct node* root = NULL;
FILE *file;
char filename[15];
char buff[255];
char line[128];
strcpy(filename, "file.txt");
file = fopen(filename, "r");
if (file == NULL) {
printf("File could not be openned.\n");
exit(0);
}
while (line != NULL)
{
strcpy(line, fgets(buff, 255, file));
printf("%s", line);
}
fclose(file);
}
有什么方法可以简单地选择第一个字符,直到“”第一次出现,然后将它们转换为整数。然后选择其余数据,删除第一个“ ID”,并将其插入char变量中。
非常感谢您的帮助。
答案 0 :(得分:1)
建议使用@LP,假设每行都类似于“ 2019,blah,blah,blah”,则可以通过调用以下内容获取每行的ID:
int id = atoi(strtok(line, ","));
答案 1 :(得分:1)
如果要解析类似的文件,
.container
仅使用lex and yacc之类的解析器生成器或我最喜欢的re2c这样的解析器生成器可能会更好。
2409, blah, blah, blah
0x10,foo, bar, baz, qux
# This is more difficult.
010 , a\
a, b b\#\\\,still b,c
打印
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <assert.h>
/* Tokens. */
#define PARAM(A) A
#define STRINGISE(A) #A
#define TOKENS(X) X(ERROR), X(END), X(COMMA), X(NEWLINE), \
X(ESCAPE), X(WSP), X(NUMBER), X(WORD)
enum Token { TOKENS(PARAM) };
static const char *const tokens[] = { TOKENS(STRINGISE) };
struct Lexer { size_t line; char *marker, *from, *cursor; };
static enum Token lex(struct Lexer *lexer) {
assert(lexer);
/*!re2c
re2c:yyfill:enable = 0;
re2c:define:YYCTYPE = char;
re2c:define:YYCURSOR = lexer->cursor;
re2c:define:YYMARKER = lexer->marker; // Rules overlap.
newline = "\n" | ("\r" "\n"?);
oct = "0" [0-7]*;
dec = [1-9][0-9]*;
hex = '0x' [0-9a-fA-F]+;
num = oct | dec | hex;
word = [^\x00\\\n\r \t\v\f,0-9]+;
comment = "#" [^\x00\n\r]* newline;
*/
scan:
lexer->from = lexer->cursor;
/*!re2c
* { return ERROR; }
"\x00" { return END; }
[ \t\v\f]+ { return WSP; }
newline { lexer->line++; return NEWLINE; }
"\\\n" | comment { lexer->line++; goto scan; }
"\\\\" | "\\," | "\\ " | "\\n" | "\\#" { return ESCAPE; }
"," { return COMMA; }
word { return WORD; }
num { return NUMBER; }
*/
}
struct Buffer {
char *data;
size_t size, capacity;
};
static char *buffer_reserve(struct Buffer *const buf, const size_t reserve) {
const size_t min = buf->size + reserve;
size_t c = buf->capacity;
char *data;
assert(buf);
if(reserve > (size_t)-1 - buf->size || min > ((size_t)-1 >> 1) + 1)
{ errno = ERANGE; return 0; }
if(min > c) {
if(!c) c = 1;
while(min <= c) c <<= 1;
if(!(data = realloc(buf->data, c))) return 0;
buf->data = data;
buf->capacity = c;
}
return buf->data + buf->size;
}
struct Word { char *start, *end; };
struct Parser {
int id, id_set, first_comma;
size_t num_words;
struct Word words[64]; /* Lazy. */
char *start_words, *end_words;
};
static size_t parser_max_words = sizeof ((struct Parser *)0)->words
/ sizeof *((struct Parser *)0)->words;
static void clear_parser(struct Parser *const parser) {
assert(parser);
parser->id_set = 0;
parser->first_comma = 1;
parser->num_words = 0;
parser->start_words = parser->end_words = 0;
}
static void print_parser(const struct Parser *const parser) {
const struct Word *word = parser->words,
*word_end = parser->words + parser->num_words;
assert(parser && parser->id_set && parser->num_words <= parser_max_words);
printf("#%d: ", parser->id);
for( ; word < word_end; word++) {
if(word != parser->words) printf(", ");
if(!word->start) { printf("<null>"); continue; }
assert(word->start <= word->end);
if(word->start == word->end) { printf("<empty>"); continue; }
printf("<%.*s>", (int)(word->end - word->start), word->start);
}
fputc('\n', stdout);
}
static void expand_word(struct Parser *const parser,
const struct Lexer *const lexer) {
assert(parser && lexer && lexer->from < lexer->cursor);
if(!parser->start_words) {
assert(!parser->end_words);
parser->start_words = lexer->from;
}
parser->end_words = (lexer->from + INT_MAX >= lexer->cursor) ?
lexer->cursor : lexer->from + INT_MAX;
}
static int store_word(struct Parser *const parser) {
struct Word *word;
assert(parser);
if(parser->num_words >= parser_max_words) return errno = EILSEQ, 0;
word = parser->words + parser->num_words++;
word->start = parser->start_words;
word->end = parser->end_words;
parser->start_words = parser->end_words = 0;
return 1;
}
int main(int argc, char **argv) {
const size_t granularity = 1024;
struct Lexer lexer = { 1, 0, 0, 0 };
struct Parser parser;
size_t nread;
struct Buffer buf = { 0, 0, 0 };
char *b;
FILE *fp = 0;
int success = 0, end_of_buffer = 0;
/* Open. */
if(argc != 2) return fprintf(stderr, "Needs filename.\n"), EXIT_FAILURE;
if(!(fp = fopen(argv[1], "r"))) goto catch;
/* Read. */
do {
if(!(b = buffer_reserve(&buf, granularity))) goto catch;
nread = fread(b, 1, granularity, fp);
buf.size += nread;
} while(nread == granularity);
if(ferror(fp)) goto catch;
fclose(fp), fp = 0;
if(!(b = buffer_reserve(&buf, 1))) goto catch;
*b = '\0'; /* Make sure it's a string. */
/* Parse. */
lexer.cursor = buf.data;
clear_parser(&parser);
do {
enum Token tok;
switch((tok = lex(&lexer))) {
case ERROR: goto catch;
case END: end_of_buffer = 1; break;
case COMMA:
if(!parser.id_set) { errno = EILSEQ; goto catch; }
if(parser.first_comma) { parser.first_comma = 0; break; }
if(!store_word(&parser)) goto catch;
break;
case NEWLINE:
if(parser.id_set) {
/* We require at least key, data. */
if(!store_word(&parser)) goto catch;
print_parser(&parser);
clear_parser(&parser);
} else if(parser.start_words) {
errno = EILSEQ; goto catch;
}
break;
case ESCAPE:
if(!parser.id_set) { errno = EILSEQ; goto catch; }
expand_word(&parser, &lexer);
break;
case WSP: break;
case NUMBER:
if(parser.id_set) {
expand_word(&parser, &lexer);
} else {
char *end;
long i = strtol(lexer.from, &end, 0);
if(end != lexer.cursor || i < INT_MIN || i > INT_MAX)
{ errno = EDOM; goto catch; }
parser.id = (int)i;
parser.id_set = 1;
}
break;
case WORD:
expand_word(&parser, &lexer);
break;
}
} while(!end_of_buffer);
success = EXIT_SUCCESS;
goto finally;
catch:
fprintf(stderr, "While on line %lu.\n", (unsigned long)lexer.line);
perror("parsing");
assert(!lexer.from || (lexer.from < lexer.cursor
&& lexer.from + INT_MAX >= lexer.cursor));
if(lexer.from) fprintf(stderr, "While on %.*s.\n",
(int)(lexer.cursor - lexer.from), lexer.from);
finally:
free(buf.data);
if(fp) fclose(fp);
return success;
}
但这可能是过分的。
答案 2 :(得分:1)
正如@ HAL9000所述,我能够使用sscanf完成此操作。只需使用sscanf(line, "%d %[^\n]s", &ID, details);
我确实尝试过使用strtok,但是由于它无法正常工作,我无法理解。 sscanf最容易做到,这就是我要使用的,谢谢。
答案 3 :(得分:0)
使用sscanf
例如
int main(int argc, char *argv[]) {
const char *str = "123, this, is, a test ;@#";
char buff[128] = {0};
int num = 0;
if (2 == sscanf(str, "%d,%[^\r\n]s", &num, buff))
printf("== num: %d, string: '%s'\n", num, buff);
else
printf("== Wrong!\n");
return 0;
}
结果:== num: 123, string: ' this, is, a test ;@#'