跳过特定行并在 C 中存储变量特定变量
Skipping specific lines and storing variables specific variables in C
这是一个简单的问题,但我似乎无法弄明白。我需要一点帮助。我有一个名为 programFile 的文件,如下所示:
start mul val1
<--tab-->ldb #2
<--tab-->addr A B
<--tab-->float
loop lda #1
<--tab-->sta val2
<--tab-->j loop
val1 word 12
val2 word 0
我只想获取不以制表符开头的行并对它们做一些处理(现在我只想打印该行中的第一个单词),所以只有行 start mul val1
, loop lda #1
、val1 word 12
和 val2 word 0
。输出应该是:
start
loop
val1
val2
最后,我也想把以制表符开头的行做一些不同的事情,但这是我解决它的失败尝试:
while(ch = fgetc(programFile) != EOF){
if(ch == '\t'){
while(ch != '\n'){
ch = fgetc(programFile);
}
}else{
fscanf(programFile, "%s", symbol);
printf("%s\n", symbol);
}
}
这是我的输出:
tart
ldb
addr
float
loop
sta
j
val1
val2
我想你可能在 ldb、addr、float、stat、j 之前使用四个 ' ' 而不是 '\t'。以下可能有效。
#include <stdio.h>
#include <string.h>
int main (int argc, const char *argv[])
{
char str[100];
FILE* pointer_file = fopen("test", "r");
while (fgets(str, sizeof str, pointer_file) != NULL )
if (str[0] != '\t') {
fputs(strtok(str, " \t\n"), stdout);
fputs("\n", stdout );
}
fclose(pointer_file);
return 0;
}
继续评论,虽然在需要时使用 面向字符的 输入函数(例如 fgetc
、getc
)并没有错处理 "lines" 的数据,你最好使用 C 库提供的 line-oriented 输入函数 (fgets
) 或 POSIX (getline
) 然后从每一行解析所需的信息。
为什么?基本上,方便和效率。面向行的输入函数提供 缓冲 读取(每次读取多个字符)并且对于大型输入文件可以真正帮助文件 I/O。接下来,无论内容如何,都会读取整行(前提是使用fgets
时有足够的行存储空间——否则会分块读取,直到读取完整行;getline
会自动分配(和重新分配)足够的存储空间来容纳每一行)。
然后您就可以使用 sscanf
、strtok
、strsep
、strstr
、strchr
等工具来解析您想要的任何内容需要从存储的行。 (你也可以 always 使用简单的 指针算法 来解析带有指针或一对指针的任何行,“遍历string" 并比较每个字符)存储字符串中每个字符的内存操作比同时对每个字符执行文件 I/O 执行相同操作快几个数量级.
当您关心每一行的起始字符时,您只需将 line[0]
(或简称 *line
)与您要查找的任何字符进行比较。
下面是一个简单的例子,它从作为第一个参数给出的输入文件名中读取(如果没有给出文件名,则默认从 stdin
读取),然后测试每一行的起始字符。如果该行以 tab
开头,它只输出以 tab
开头的行(在通过输出 line + 1
从文件中跳过 tab
之后)后跟 -- begins with tab
(你可以随意处理这些行,或者完全跳过它们),否则它会输出行本身后跟 -- no tab
。不同前缀行的处理完全取决于您。如果需要,您可以构建一个指针数组来保存每种不同类型的行,或者使用包含指针数组中的命令和选项卡式内容的结构来保留行关联(哪些命令与哪些选项卡式行对应)。
关于 line-oriented 输入函数的唯一其他注意事项是它们读取 直到并包括 尾随 '\n'
.您通常不希望存储带有 newlines
悬空的字符串,因此您需要 trim newlines
通过用 [=75= 覆盖尾随 '\n'
]nul 终止符。该示例通过使用 strlen
获取每行的长度,然后使用 0
(相当于字符 '[=43=]'
)覆盖 newline
来实现这一点。我不喜欢打字...
#include <stdio.h>
#include <string.h>
#define MAX 64
int main (int argc, char **argv) {
char line[MAX] = "";
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (line, MAX, fp)) /* read each line in file */
{
size_t len = strlen (line); /* get the length */
if (line[len - 1] == '\n') /* check for trailing '\n' */
line[--len] = 0; /* overwrite with nul-byte */
if (*line == '\t') { /* if first char is '\t' */
printf ("\t%s - begins with tab\n", line + 1);
continue;
}
printf ("%s - no tab\n", line); /* line has no tab */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
输入文件
$ cat dat/tabfile.txt
start mul val1
ldb #2
addr A B
float
loop lda #1
sta val2
j loop
val1 word 12
val2 word 0
例子Use/Output
$ ./bin/filehandletab <dat/tabfile.txt
start mul val1 - no tab
ldb #2 - begins with tab
addr A B - begins with tab
float - begins with tab
loop lda #1 - no tab
sta val2 - begins with tab
j loop - begins with tab
val1 word 12 - no tab
val2 word 0 - no tab
正如评论中所指出的,如果您的意图是从不以 tab
开头的行中解析第一个单词,那么您可以简单地使用 strchr
来定位第一个 space
,在 space
处临时终止行使用命令,然后恢复 space
以便在需要时可以第二次进一步解析字符串,例如
while (fgets (line, MAX, fp))
{
char *p = NULL;
size_t len = strlen (line);
...
if (*line == '\t') { /* if first char is '\t' */
printf ("\t%s - begins with tab\n", line + 1);
continue;
}
if ((p = strchr (line, ' '))) { /* find first ' ' */
*p = 0; /* terminate at p */
printf ("%s - no tab\n", line); /* output line */
*p = ' '; /* restore ' ' */
}
else
printf ("%s - no tab\n", line); /* s has no tab */
}
或者,编写相同的行终止符,删除 if...else...
和重复的 printf
,您可以使用更紧凑但可读性较差的代码(完全向上给你):
if ((p = strchr (line, ' '))) /* find first ' ' */
*p = 0; /* terminate at p */
printf ("%s - no tab\n", line); /* s has no tab */
if (p) /* if terminated */
*p = ' '; /* restore ' ' */
例子Use/Output
$ ./bin/filehandletab <dat/tabfile.txt
start - no tab
ldb #2 - begins with tab
addr A B - begins with tab
float - begins with tab
loop - no tab
sta val2 - begins with tab
j loop - begins with tab
val1 - no tab
val2 - no tab
检查一下,如果您有任何其他问题,请告诉我。
要么读取整行并解析它们,要么读取字符以驱动有限状态机,例如:
#include <stdio.h>
int main(void)
{
int ch, state;
for (state =0; ; ) {
ch = getc(stdin) ;
if (ch==EOF) break;
switch(state) {
case 0: /* initial */
if (ch == '\t') {state = 2; continue; }
if (ch == '\n') { continue; } /* empty line */
state = 1;
break; /* break will emit the character */
case 1: /* first word on the line */
if (ch== ' ') {ch = '\n'; state =2; break; }
if (ch== '\n') {state =0; break; }
break;
case 2: /* ignore until EOL */
if (ch== '\n') {state =0; continue; }
continue;
}
putc(ch, stdout);
}
return 0;
}
这是一个简单的问题,但我似乎无法弄明白。我需要一点帮助。我有一个名为 programFile 的文件,如下所示:
start mul val1
<--tab-->ldb #2
<--tab-->addr A B
<--tab-->float
loop lda #1
<--tab-->sta val2
<--tab-->j loop
val1 word 12
val2 word 0
我只想获取不以制表符开头的行并对它们做一些处理(现在我只想打印该行中的第一个单词),所以只有行 start mul val1
, loop lda #1
、val1 word 12
和 val2 word 0
。输出应该是:
start
loop
val1
val2
最后,我也想把以制表符开头的行做一些不同的事情,但这是我解决它的失败尝试:
while(ch = fgetc(programFile) != EOF){
if(ch == '\t'){
while(ch != '\n'){
ch = fgetc(programFile);
}
}else{
fscanf(programFile, "%s", symbol);
printf("%s\n", symbol);
}
}
这是我的输出:
tart
ldb
addr
float
loop
sta
j
val1
val2
我想你可能在 ldb、addr、float、stat、j 之前使用四个 ' ' 而不是 '\t'。以下可能有效。
#include <stdio.h>
#include <string.h>
int main (int argc, const char *argv[])
{
char str[100];
FILE* pointer_file = fopen("test", "r");
while (fgets(str, sizeof str, pointer_file) != NULL )
if (str[0] != '\t') {
fputs(strtok(str, " \t\n"), stdout);
fputs("\n", stdout );
}
fclose(pointer_file);
return 0;
}
继续评论,虽然在需要时使用 面向字符的 输入函数(例如 fgetc
、getc
)并没有错处理 "lines" 的数据,你最好使用 C 库提供的 line-oriented 输入函数 (fgets
) 或 POSIX (getline
) 然后从每一行解析所需的信息。
为什么?基本上,方便和效率。面向行的输入函数提供 缓冲 读取(每次读取多个字符)并且对于大型输入文件可以真正帮助文件 I/O。接下来,无论内容如何,都会读取整行(前提是使用fgets
时有足够的行存储空间——否则会分块读取,直到读取完整行;getline
会自动分配(和重新分配)足够的存储空间来容纳每一行)。
然后您就可以使用 sscanf
、strtok
、strsep
、strstr
、strchr
等工具来解析您想要的任何内容需要从存储的行。 (你也可以 always 使用简单的 指针算法 来解析带有指针或一对指针的任何行,“遍历string" 并比较每个字符)存储字符串中每个字符的内存操作比同时对每个字符执行文件 I/O 执行相同操作快几个数量级.
当您关心每一行的起始字符时,您只需将 line[0]
(或简称 *line
)与您要查找的任何字符进行比较。
下面是一个简单的例子,它从作为第一个参数给出的输入文件名中读取(如果没有给出文件名,则默认从 stdin
读取),然后测试每一行的起始字符。如果该行以 tab
开头,它只输出以 tab
开头的行(在通过输出 line + 1
从文件中跳过 tab
之后)后跟 -- begins with tab
(你可以随意处理这些行,或者完全跳过它们),否则它会输出行本身后跟 -- no tab
。不同前缀行的处理完全取决于您。如果需要,您可以构建一个指针数组来保存每种不同类型的行,或者使用包含指针数组中的命令和选项卡式内容的结构来保留行关联(哪些命令与哪些选项卡式行对应)。
关于 line-oriented 输入函数的唯一其他注意事项是它们读取 直到并包括 尾随 '\n'
.您通常不希望存储带有 newlines
悬空的字符串,因此您需要 trim newlines
通过用 [=75= 覆盖尾随 '\n'
]nul 终止符。该示例通过使用 strlen
获取每行的长度,然后使用 0
(相当于字符 '[=43=]'
)覆盖 newline
来实现这一点。我不喜欢打字...
#include <stdio.h>
#include <string.h>
#define MAX 64
int main (int argc, char **argv) {
char line[MAX] = "";
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (line, MAX, fp)) /* read each line in file */
{
size_t len = strlen (line); /* get the length */
if (line[len - 1] == '\n') /* check for trailing '\n' */
line[--len] = 0; /* overwrite with nul-byte */
if (*line == '\t') { /* if first char is '\t' */
printf ("\t%s - begins with tab\n", line + 1);
continue;
}
printf ("%s - no tab\n", line); /* line has no tab */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
输入文件
$ cat dat/tabfile.txt
start mul val1
ldb #2
addr A B
float
loop lda #1
sta val2
j loop
val1 word 12
val2 word 0
例子Use/Output
$ ./bin/filehandletab <dat/tabfile.txt
start mul val1 - no tab
ldb #2 - begins with tab
addr A B - begins with tab
float - begins with tab
loop lda #1 - no tab
sta val2 - begins with tab
j loop - begins with tab
val1 word 12 - no tab
val2 word 0 - no tab
正如评论中所指出的,如果您的意图是从不以 tab
开头的行中解析第一个单词,那么您可以简单地使用 strchr
来定位第一个 space
,在 space
处临时终止行使用命令,然后恢复 space
以便在需要时可以第二次进一步解析字符串,例如
while (fgets (line, MAX, fp))
{
char *p = NULL;
size_t len = strlen (line);
...
if (*line == '\t') { /* if first char is '\t' */
printf ("\t%s - begins with tab\n", line + 1);
continue;
}
if ((p = strchr (line, ' '))) { /* find first ' ' */
*p = 0; /* terminate at p */
printf ("%s - no tab\n", line); /* output line */
*p = ' '; /* restore ' ' */
}
else
printf ("%s - no tab\n", line); /* s has no tab */
}
或者,编写相同的行终止符,删除 if...else...
和重复的 printf
,您可以使用更紧凑但可读性较差的代码(完全向上给你):
if ((p = strchr (line, ' '))) /* find first ' ' */
*p = 0; /* terminate at p */
printf ("%s - no tab\n", line); /* s has no tab */
if (p) /* if terminated */
*p = ' '; /* restore ' ' */
例子Use/Output
$ ./bin/filehandletab <dat/tabfile.txt
start - no tab
ldb #2 - begins with tab
addr A B - begins with tab
float - begins with tab
loop - no tab
sta val2 - begins with tab
j loop - begins with tab
val1 - no tab
val2 - no tab
检查一下,如果您有任何其他问题,请告诉我。
要么读取整行并解析它们,要么读取字符以驱动有限状态机,例如:
#include <stdio.h>
int main(void)
{
int ch, state;
for (state =0; ; ) {
ch = getc(stdin) ;
if (ch==EOF) break;
switch(state) {
case 0: /* initial */
if (ch == '\t') {state = 2; continue; }
if (ch == '\n') { continue; } /* empty line */
state = 1;
break; /* break will emit the character */
case 1: /* first word on the line */
if (ch== ' ') {ch = '\n'; state =2; break; }
if (ch== '\n') {state =0; break; }
break;
case 2: /* ignore until EOL */
if (ch== '\n') {state =0; continue; }
continue;
}
putc(ch, stdout);
}
return 0;
}