fgets 在遇到 space 时停止
fgets to stop when a space is encountered
我正在尝试用 C 语言解析一个输入 JSON 文件,该文件的内容类似于:{"version":"0.1","type":"tracbuf:e", "userid":0, "method":"udpbuf:-paris", "src":"10.20.6.191"buf:, "dst":"8.8.8.8", "sport":41buf:687, "dport":33435, ...
输入文件很大,我想读取每一行并解析读取的行,即分别分隔键值对,行和键值字段的长度任意。
我知道 fscanf()
可以很好地工作。但我想使用一些具有边界保护的功能,例如 fgets()
。但我不太确定在这种情况下如何使用 fgets(),因为它将 'n' 字节读入缓冲区,包括换行符、制表符 space 和 blankspace('')
。但是我希望能够在遇到空白 space / tab space/ 换行符时中断,以便在进一步阅读其他行之前解析读取的字符。
请注意 fscanf()
可以与 strtok()
一起执行此操作 - 它会在每一行 space/new 处中断。但遗憾的是,它不允许缓冲区有界限。
我该怎么办?
更新编辑:
以下方法有效。在每个条件中,我需要调用 strtok 并进行大约 6 次比较。但我想知道是否可以做得更好
while(fscanf(fp, "%100s", buf) != EOF)
{
token=strtok(buf,":-");
while(token!=NULL)
{
if(strcmp(token,"\"src\"")==0)
{
head[trace_count]=(HEADER*) malloc(sizeof(HEADER));
token=strtok(NULL,":{,}])");
strcpy(head[trace_count]->src_ip,token);
}
else if(strcmmp(...))
{
}
...
}
由于行可以是任意长度,因此将行读入缓冲区总是会遇到问题;缓冲区可能永远不够大。唯一的方法是通过字符处理。以下是您的语法的简单、基本的解析器。根据需要进行调整:
void example(FILE *fin)
{
char c, token[MAX_TOKEN], tokval[MAX_SVAL], *s= token;
int instr= FALSE; // track whether we are in a string
int intok= TRUE; // track whether we are in a token name or a value
while ((c=fgetc(fin)) != EOF)
{
if (instr) {
if (c=='"')
{*s='[=10=]'; instr= FALSE;}
else *s++ = c;
}
else switch (c) {
case '"': instr= TRUE; break;
case '{': /* open: whatever you want to do*/ break;
case '}': /* close: whatever you want to do*/ break;
case ':': if (intok) {*s= '[=10=]'; s= tokval; intok= FALSE; /* have token name now*/} else *s++ = ':'; break;
case ',': if (!intok) {*s= '[=10=]'; s= token; intok= TRUE; /* have a pair now */} else *s++ = ','; break;
case ' ': case '\t': case '\n': case '\r': break;
default: *s++ = c;
}
if (intok)
{if (s > token+MAX_TOKEN-2) error("token name too long");}
else {if (s > tokval+MAX_SVAL-2) error("token value too long");}
}
}
我正在尝试用 C 语言解析一个输入 JSON 文件,该文件的内容类似于:{"version":"0.1","type":"tracbuf:e", "userid":0, "method":"udpbuf:-paris", "src":"10.20.6.191"buf:, "dst":"8.8.8.8", "sport":41buf:687, "dport":33435, ...
输入文件很大,我想读取每一行并解析读取的行,即分别分隔键值对,行和键值字段的长度任意。
我知道 fscanf()
可以很好地工作。但我想使用一些具有边界保护的功能,例如 fgets()
。但我不太确定在这种情况下如何使用 fgets(),因为它将 'n' 字节读入缓冲区,包括换行符、制表符 space 和 blankspace('')
。但是我希望能够在遇到空白 space / tab space/ 换行符时中断,以便在进一步阅读其他行之前解析读取的字符。
请注意 fscanf()
可以与 strtok()
一起执行此操作 - 它会在每一行 space/new 处中断。但遗憾的是,它不允许缓冲区有界限。
我该怎么办?
更新编辑:
以下方法有效。在每个条件中,我需要调用 strtok 并进行大约 6 次比较。但我想知道是否可以做得更好
while(fscanf(fp, "%100s", buf) != EOF)
{
token=strtok(buf,":-");
while(token!=NULL)
{
if(strcmp(token,"\"src\"")==0)
{
head[trace_count]=(HEADER*) malloc(sizeof(HEADER));
token=strtok(NULL,":{,}])");
strcpy(head[trace_count]->src_ip,token);
}
else if(strcmmp(...))
{
}
...
}
由于行可以是任意长度,因此将行读入缓冲区总是会遇到问题;缓冲区可能永远不够大。唯一的方法是通过字符处理。以下是您的语法的简单、基本的解析器。根据需要进行调整:
void example(FILE *fin)
{
char c, token[MAX_TOKEN], tokval[MAX_SVAL], *s= token;
int instr= FALSE; // track whether we are in a string
int intok= TRUE; // track whether we are in a token name or a value
while ((c=fgetc(fin)) != EOF)
{
if (instr) {
if (c=='"')
{*s='[=10=]'; instr= FALSE;}
else *s++ = c;
}
else switch (c) {
case '"': instr= TRUE; break;
case '{': /* open: whatever you want to do*/ break;
case '}': /* close: whatever you want to do*/ break;
case ':': if (intok) {*s= '[=10=]'; s= tokval; intok= FALSE; /* have token name now*/} else *s++ = ':'; break;
case ',': if (!intok) {*s= '[=10=]'; s= token; intok= TRUE; /* have a pair now */} else *s++ = ','; break;
case ' ': case '\t': case '\n': case '\r': break;
default: *s++ = c;
}
if (intok)
{if (s > token+MAX_TOKEN-2) error("token name too long");}
else {if (s > tokval+MAX_SVAL-2) error("token value too long");}
}
}