如何在文件中搜索一个单词,将其放入一个数组中,然后在 C 中将其删除
How to search for a word in a file, put it in an array then delete it in C
我刚开始学习C。我的第一个项目是一个程序,它从文本文件中读取文本,然后根据文件中的命令对其进行格式化。
我解决这个问题的方法是让程序扫描文本文件,找到命令,将它们从文本文件中删除,然后将它们放入数组中。然后 运行 文本的其余部分通过每个命令的 if 语句。
例如,如果命令是删除多余的空格,它会从代码中删除多余的空格等等。到目前为止,我只有一个代码可以读取文件并将其打印出来
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char *filename;
char ch;
// Check if a filename has been specified in the command
if (argc < 2)
{
printf("Missing Filename\n");
return(1);
}
else
{
filename = argv[1];
printf("Filename : %s\n", filename);
}
// Open file in read-only mode
fp = fopen(filename,"r");
// If file opened successfully, then print the contents
if ( fp )
{
printf("File contents:\n");
while ( (ch = fgetc(fp)) != EOF )
{
printf("%c",ch);
}
}
else
{
printf("Failed to open the file\n");
}
return(0);
}
我应该指出,这段代码不完全是我的。
我的问题是。我正在尝试编写一段代码来扫描文本文件,找到一个特定的单词,将其从文本文件中删除并将其保存在一个数组中。而已。一旦在文本文件中找到了这个词,它就被保存在一个数组中,然后从文本文件中删除。这个词将是一个格式化选项。然后文本根据选项的内容进行格式化,然后打印到另一个文本文件中。
例如,扫描一段文字,发现"LW30"这个词意味着每行最多只能有30个字符。一旦程序找到这个选项,它就会根据选项的含义来格式化文本。它可能有多个选项,每个选项都意味着不同的东西,但只有 5 个可能的选项,当然,它会读取一个随机文本文件,所以我不知道选项是什么。
格式化命令为:
.LW(width) 每行被格式化,因此每行不超过 'width' 个字符
.LM(left) 这里命令后面的每一行将从左边距缩进 'left' 个空格。缩进包含在页面宽度中。
.FT[off|on] 这个用来打开和关闭格式化。如果命令以 "off" 出现,则命令下方的所有文本直至下一个“.FT"command is output without being formatted. If it appears with "on”,然后命令下方直至下一个“.FT”命令的所有文本将输出为填满给定页面宽度的字数
.LS(linespacing) 如果 "linespacing" 不为零 (0) 则每个文本行之间将出现行距空行。输入文件中的空行被认为与文本行相同。
此外,每个命令在文本中都有自己的一行
非常感谢您对此提供帮助。
就是那种需要分解成小问题才能轻松解决的问题。
每行读取输入文件行
一个。如果是格式化命令,用格式化选项改变程序的状态
b。否则将正确格式化的行打印到临时文件
用临时文件的内容覆盖输入文件。
首先,让我们定义几个稍后将被重用的类型。如果你是 C 的新手,我邀请你检查 this page 并阅读什么是 enum
、struct
和 union
。
可能命令的列举
typedef enum Command_e { CMD_NONE, LW , LM , FT , LS } Command;
各种线路的列举。基本上你有两种行:要格式化的常规行和包含命令的行
typedef enum LineType_e { LT_NONE, REGULAR , COMMAND } LineType;
表示直线的结构。一行包含它的类型。此外,REGULAR
行包含其长度和内容。 COMMAND
包含它的类型和它的参数。我们将 on
和 off
值分别表示为 1
和 0
。
typedef struct Line_s
{
LineType type;
union
{
struct cmd_s
{
Command type;
int arg;
} cmd;
struct reg_s
{
char * str;
size_t len;
} reg;
} content;
} Line;
在 C 中,没有标准的 getline
函数。但是,使用 fgets
函数很容易做到这一点。
// Read a line from the stream and returns a string containing every
// characters of the line until a newline character is read or end-of-file
// is reached. size is filled with the size of the string including the
// newline character.
// If end-of-file is reached before any character is read, the function
// returns NULL
char * getline(FILE * stream, size_t * s)
{
char * buf = NULL; // Buffer to return
int cnt = 0;
int size = 0; // Buffer size
int start = 0; // Where to start writing in the buffer
do
{
// Resize the buffer to (2^cnt * BUFF_SIZE) and fill the expanded
// part with the a null character
size = BUFF_SIZE * (1 << cnt);
start = BUFF_SIZE * (1 << (cnt - 1)) - 1;
start = start < 0 ? 0 : start;
buf = realloc(buf, size * sizeof(char));
memset(& buf[start], '[=13=]', size - start);
// Read a maximum of (size - start) characters from the stream or
// until a newline character has been reached
fgets(& buf[start], size - start, stream);
cnt ++;
} // Loop until a complete line has been read
while(buf[size - 2] != '[=13=]' &&
buf[size - 2] != '\n' &&
! feof(stdin));
// If nothing has been read from the file, free the memory and returns
// a NULL pointer
if(buf[0] == '[=13=]')
{
free(buf);
buf = NULL;
(* s) = 0;
}
else
{
(* s) = strlen(buf);
}
return buf;
}
其中 BUFF_SIZE
是定义缓冲区典型大小的宏。此函数需要包含 string.h
,因为它使用 memset
和 stdlib.h
才能使用 realloc
.
鉴于此函数,您可以轻松编写另一个函数,该函数将每行读取文件行并将填充作为输入传递的 Line
结构和 return 如果结束则为零的整数已到达-of-file。
int getNextLine(FILE * stream, Line * line)
{
size_t size;
char * str = getline(stream, & size);
if(! str)
{
line->type = LT_NONE;
return 0;
}
str[size - 1] = '[=14=]'; // Remove the newline character
if(size - 1 > 2)
{
if(str[0] == 'L' && (str[1] == 'W' || str[1] == 'M' || str[1] == 'S'))
{
// If the remaining of the string is made characters between '0' and
// '9', then, str is a LW, LM or LS command
int val = 0;
int i;
for(i = 2; i < size - 1; i ++)
{
if(str[i] < '0' || str[i] > '9') break;
val = val * 10 + (str[i] - '0');
}
if(i < size - 1)
{
line->type = REGULAR;
line->content.reg.str = str;
line->content.reg.len = size;
}
else
{
line->type = COMMAND;
line->content.cmd.arg = val;
switch(str[1])
{
case 'W' : line->content.cmd.type = LW; break;
case 'M' : line->content.cmd.type = LM; break;
case 'S' : line->content.cmd.type = LS; break;
}
}
return 1;
}
if(size - 1 == 4 && str[0] == 'F' && str[1] == 'T' &&
str[2] == 'o' && str[3] == 'n')
{
// FTon command found
line->type = COMMAND;
line->content.cmd.type = FT;
line->content.cmd.arg = 1;
return 1;
}
if(size - 1 == 5 && str[0] == 'F' && str[1] == 'T' &&
str[2] == 'o' && str[3] == 'f' && str[4] == 'f')
{
// FToff command found
line->type = COMMAND;
line->content.cmd.type = FT;
line->content.cmd.arg = 0;
return 1;
}
}
// If we reach this point no command have been found
line->type = REGULAR;
line->content.reg.str = str;
line->content.reg.len = size;
return 1;
}
现在,您几乎完成了。在 getNextLine
将 return 0
时停止的主循环中,您可以根据收到的命令设置一些变量,当您收到常规行时,您可以调用format 函数,它将按照流中应有的格式输出行。这是此类函数的示例。
void format(FILE * stream, Line line, int ft, int lw, int lm, int ls)
{
if(! ft)
{
// If the formatting is disabled, simply send the line to the stream
fprintf(stream, "%s\n", line.content.reg.str);
}
else
{
int i;
int j;
char f[16] = { 0 };
sprintf(f, "%%.%ds\n", lw - lm);
i = 0;
do
{
for(j = 0; j < lm; j ++) fprintf(stream, " ");
fprintf(stream, f, & line.content.reg.str[i * (lw - lm)]);
for(j = 0; j < ls; j ++) fprintf(stream, "\n");
i++;
}
while(i * (lw - lm) < line.content.reg.len);
}
}
之前说的临时文件可以用tmpfile
功能打开。当您到达输入文件的末尾时,您只需关闭输入文件并将临时文件的内容复制到其中。这只需使用 buffers
和 fprintf
即可完成。不要忘记在将格式化行打印到临时文件后调用 free
函数释放内存,以避免内存泄漏。
最后,像
这样的文件
FTon
LW30
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam est arcu, congue vehicula consectetur in, tempus ac ex. Integer urna lectus, maximus vel felis sed, dapibus gravida risus. Curabitur diam arcu, accumsan at magna id, laoreet condimentum ante.
FToff
Nulla id velit justo. Aenean leo risus, interdum lobortis enim sit amet, aliquet elementum dolor. Morbi pretium velit sed mauris molestie viverra. Cras ut cursus nibh. Aliquam ut aliquam nunc, eget rhoncus sapien.
LS1
Sed efficitur justo aliquam orci molestie, vel condimentum dui semper. Sed lobortis dignissim ligula ut bibendum. Pellentesque finibus euismod massa a congue.
FTon
Sed placerat quam eget ante rutrum pretium a in orci. Quisque id lorem dapibus, tincidunt lorem et, convallis orci. Etiam sed placerat ante.
LM5
Donec mi est, sodales sed faucibus ac, elementum eu velit. Nam mollis varius porttitor. Sed dignissim sodales malesuada.
LW15
Donec nec tempus turpis, at condimentum velit.
会给你下面的输出
Lorem ipsum dolor sit amet, co
nsectetur adipiscing elit. Ali
quam est arcu, congue vehicula
consectetur in, tempus ac ex.
Integer urna lectus, maximus
vel felis sed, dapibus gravida
risus. Curabitur diam arcu, a
ccumsan at magna id, laoreet c
ondimentum ante.
Nulla id velit justo. Aenean leo risus, interdum lobortis enim sit amet, aliquet elementum dolor. Morbi pretium velit sed mauris molestie viverra. Cras ut cursus nibh. Aliquam ut aliquam nunc, eget rhoncus sapien.
Sed efficitur justo aliquam orci molestie, vel condimentum dui semper. Sed lobortis dignissim ligula ut bibendum. Pellentesque finibus euismod massa a congue.
Sed placerat quam eget ante ru
trum pretium a in orci. Quisqu
e id lorem dapibus, tincidunt
lorem et, convallis orci. Etia
m sed placerat ante.
Donec mi est, sodales sed
faucibus ac, elementum e
u velit. Nam mollis variu
s porttitor. Sed dignissi
m sodales malesuada.
Donec nec
tempus tur
pis, at co
ndimentum
velit.
我刚开始学习C。我的第一个项目是一个程序,它从文本文件中读取文本,然后根据文件中的命令对其进行格式化。
我解决这个问题的方法是让程序扫描文本文件,找到命令,将它们从文本文件中删除,然后将它们放入数组中。然后 运行 文本的其余部分通过每个命令的 if 语句。
例如,如果命令是删除多余的空格,它会从代码中删除多余的空格等等。到目前为止,我只有一个代码可以读取文件并将其打印出来
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char *filename;
char ch;
// Check if a filename has been specified in the command
if (argc < 2)
{
printf("Missing Filename\n");
return(1);
}
else
{
filename = argv[1];
printf("Filename : %s\n", filename);
}
// Open file in read-only mode
fp = fopen(filename,"r");
// If file opened successfully, then print the contents
if ( fp )
{
printf("File contents:\n");
while ( (ch = fgetc(fp)) != EOF )
{
printf("%c",ch);
}
}
else
{
printf("Failed to open the file\n");
}
return(0);
}
我应该指出,这段代码不完全是我的。
我的问题是。我正在尝试编写一段代码来扫描文本文件,找到一个特定的单词,将其从文本文件中删除并将其保存在一个数组中。而已。一旦在文本文件中找到了这个词,它就被保存在一个数组中,然后从文本文件中删除。这个词将是一个格式化选项。然后文本根据选项的内容进行格式化,然后打印到另一个文本文件中。
例如,扫描一段文字,发现"LW30"这个词意味着每行最多只能有30个字符。一旦程序找到这个选项,它就会根据选项的含义来格式化文本。它可能有多个选项,每个选项都意味着不同的东西,但只有 5 个可能的选项,当然,它会读取一个随机文本文件,所以我不知道选项是什么。
格式化命令为:
.LW(width) 每行被格式化,因此每行不超过 'width' 个字符
.LM(left) 这里命令后面的每一行将从左边距缩进 'left' 个空格。缩进包含在页面宽度中。
.FT[off|on] 这个用来打开和关闭格式化。如果命令以 "off" 出现,则命令下方的所有文本直至下一个“.FT"command is output without being formatted. If it appears with "on”,然后命令下方直至下一个“.FT”命令的所有文本将输出为填满给定页面宽度的字数
.LS(linespacing) 如果 "linespacing" 不为零 (0) 则每个文本行之间将出现行距空行。输入文件中的空行被认为与文本行相同。
此外,每个命令在文本中都有自己的一行
非常感谢您对此提供帮助。
就是那种需要分解成小问题才能轻松解决的问题。
每行读取输入文件行
一个。如果是格式化命令,用格式化选项改变程序的状态
b。否则将正确格式化的行打印到临时文件
用临时文件的内容覆盖输入文件。
首先,让我们定义几个稍后将被重用的类型。如果你是 C 的新手,我邀请你检查 this page 并阅读什么是 enum
、struct
和 union
。
可能命令的列举
typedef enum Command_e { CMD_NONE, LW , LM , FT , LS } Command;
各种线路的列举。基本上你有两种行:要格式化的常规行和包含命令的行
typedef enum LineType_e { LT_NONE, REGULAR , COMMAND } LineType;
表示直线的结构。一行包含它的类型。此外,REGULAR
行包含其长度和内容。 COMMAND
包含它的类型和它的参数。我们将 on
和 off
值分别表示为 1
和 0
。
typedef struct Line_s
{
LineType type;
union
{
struct cmd_s
{
Command type;
int arg;
} cmd;
struct reg_s
{
char * str;
size_t len;
} reg;
} content;
} Line;
在 C 中,没有标准的 getline
函数。但是,使用 fgets
函数很容易做到这一点。
// Read a line from the stream and returns a string containing every
// characters of the line until a newline character is read or end-of-file
// is reached. size is filled with the size of the string including the
// newline character.
// If end-of-file is reached before any character is read, the function
// returns NULL
char * getline(FILE * stream, size_t * s)
{
char * buf = NULL; // Buffer to return
int cnt = 0;
int size = 0; // Buffer size
int start = 0; // Where to start writing in the buffer
do
{
// Resize the buffer to (2^cnt * BUFF_SIZE) and fill the expanded
// part with the a null character
size = BUFF_SIZE * (1 << cnt);
start = BUFF_SIZE * (1 << (cnt - 1)) - 1;
start = start < 0 ? 0 : start;
buf = realloc(buf, size * sizeof(char));
memset(& buf[start], '[=13=]', size - start);
// Read a maximum of (size - start) characters from the stream or
// until a newline character has been reached
fgets(& buf[start], size - start, stream);
cnt ++;
} // Loop until a complete line has been read
while(buf[size - 2] != '[=13=]' &&
buf[size - 2] != '\n' &&
! feof(stdin));
// If nothing has been read from the file, free the memory and returns
// a NULL pointer
if(buf[0] == '[=13=]')
{
free(buf);
buf = NULL;
(* s) = 0;
}
else
{
(* s) = strlen(buf);
}
return buf;
}
其中 BUFF_SIZE
是定义缓冲区典型大小的宏。此函数需要包含 string.h
,因为它使用 memset
和 stdlib.h
才能使用 realloc
.
鉴于此函数,您可以轻松编写另一个函数,该函数将每行读取文件行并将填充作为输入传递的 Line
结构和 return 如果结束则为零的整数已到达-of-file。
int getNextLine(FILE * stream, Line * line)
{
size_t size;
char * str = getline(stream, & size);
if(! str)
{
line->type = LT_NONE;
return 0;
}
str[size - 1] = '[=14=]'; // Remove the newline character
if(size - 1 > 2)
{
if(str[0] == 'L' && (str[1] == 'W' || str[1] == 'M' || str[1] == 'S'))
{
// If the remaining of the string is made characters between '0' and
// '9', then, str is a LW, LM or LS command
int val = 0;
int i;
for(i = 2; i < size - 1; i ++)
{
if(str[i] < '0' || str[i] > '9') break;
val = val * 10 + (str[i] - '0');
}
if(i < size - 1)
{
line->type = REGULAR;
line->content.reg.str = str;
line->content.reg.len = size;
}
else
{
line->type = COMMAND;
line->content.cmd.arg = val;
switch(str[1])
{
case 'W' : line->content.cmd.type = LW; break;
case 'M' : line->content.cmd.type = LM; break;
case 'S' : line->content.cmd.type = LS; break;
}
}
return 1;
}
if(size - 1 == 4 && str[0] == 'F' && str[1] == 'T' &&
str[2] == 'o' && str[3] == 'n')
{
// FTon command found
line->type = COMMAND;
line->content.cmd.type = FT;
line->content.cmd.arg = 1;
return 1;
}
if(size - 1 == 5 && str[0] == 'F' && str[1] == 'T' &&
str[2] == 'o' && str[3] == 'f' && str[4] == 'f')
{
// FToff command found
line->type = COMMAND;
line->content.cmd.type = FT;
line->content.cmd.arg = 0;
return 1;
}
}
// If we reach this point no command have been found
line->type = REGULAR;
line->content.reg.str = str;
line->content.reg.len = size;
return 1;
}
现在,您几乎完成了。在 getNextLine
将 return 0
时停止的主循环中,您可以根据收到的命令设置一些变量,当您收到常规行时,您可以调用format 函数,它将按照流中应有的格式输出行。这是此类函数的示例。
void format(FILE * stream, Line line, int ft, int lw, int lm, int ls)
{
if(! ft)
{
// If the formatting is disabled, simply send the line to the stream
fprintf(stream, "%s\n", line.content.reg.str);
}
else
{
int i;
int j;
char f[16] = { 0 };
sprintf(f, "%%.%ds\n", lw - lm);
i = 0;
do
{
for(j = 0; j < lm; j ++) fprintf(stream, " ");
fprintf(stream, f, & line.content.reg.str[i * (lw - lm)]);
for(j = 0; j < ls; j ++) fprintf(stream, "\n");
i++;
}
while(i * (lw - lm) < line.content.reg.len);
}
}
之前说的临时文件可以用tmpfile
功能打开。当您到达输入文件的末尾时,您只需关闭输入文件并将临时文件的内容复制到其中。这只需使用 buffers
和 fprintf
即可完成。不要忘记在将格式化行打印到临时文件后调用 free
函数释放内存,以避免内存泄漏。
最后,像
这样的文件FTon
LW30
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam est arcu, congue vehicula consectetur in, tempus ac ex. Integer urna lectus, maximus vel felis sed, dapibus gravida risus. Curabitur diam arcu, accumsan at magna id, laoreet condimentum ante.
FToff
Nulla id velit justo. Aenean leo risus, interdum lobortis enim sit amet, aliquet elementum dolor. Morbi pretium velit sed mauris molestie viverra. Cras ut cursus nibh. Aliquam ut aliquam nunc, eget rhoncus sapien.
LS1
Sed efficitur justo aliquam orci molestie, vel condimentum dui semper. Sed lobortis dignissim ligula ut bibendum. Pellentesque finibus euismod massa a congue.
FTon
Sed placerat quam eget ante rutrum pretium a in orci. Quisque id lorem dapibus, tincidunt lorem et, convallis orci. Etiam sed placerat ante.
LM5
Donec mi est, sodales sed faucibus ac, elementum eu velit. Nam mollis varius porttitor. Sed dignissim sodales malesuada.
LW15
Donec nec tempus turpis, at condimentum velit.
会给你下面的输出
Lorem ipsum dolor sit amet, co
nsectetur adipiscing elit. Ali
quam est arcu, congue vehicula
consectetur in, tempus ac ex.
Integer urna lectus, maximus
vel felis sed, dapibus gravida
risus. Curabitur diam arcu, a
ccumsan at magna id, laoreet c
ondimentum ante.
Nulla id velit justo. Aenean leo risus, interdum lobortis enim sit amet, aliquet elementum dolor. Morbi pretium velit sed mauris molestie viverra. Cras ut cursus nibh. Aliquam ut aliquam nunc, eget rhoncus sapien.
Sed efficitur justo aliquam orci molestie, vel condimentum dui semper. Sed lobortis dignissim ligula ut bibendum. Pellentesque finibus euismod massa a congue.
Sed placerat quam eget ante ru
trum pretium a in orci. Quisqu
e id lorem dapibus, tincidunt
lorem et, convallis orci. Etia
m sed placerat ante.
Donec mi est, sodales sed
faucibus ac, elementum e
u velit. Nam mollis variu
s porttitor. Sed dignissi
m sodales malesuada.
Donec nec
tempus tur
pis, at co
ndimentum
velit.