我刚刚开始学习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);
}
这段代码完全不是我应该指出的。
我的问题是。我试图编写一段扫描文本文件的代码,查找特定的单词,将其从文本文件中删除并将其保存在数组中。就是这样。在文本文件中找到单词后,它将保存在一个数组中,然后从文本文件中删除。这个词将是格式化选项。然后根据选项的格式对文本进行格式化,然后将其打印到另一个文本文件中。
例如,它扫描文本并找到单词&#34; LW30&#34;这个词意味着每行最多只能有30个字符。一旦程序找到此选项,它将根据选项的含义格式化文本。它可能不止一个选项,每个意味着不同的东西,但只有5个选项可能,当然,它将读取随机文本文件,所以我不知道选项将是什么。
格式化命令是:
.LW(宽度)格式化每一行,以便永远不会超过&#39;宽度&#39;每行中的字符
.LM(左)这里命令后面的每一行都将缩进&#39; left&#39;左边距离的空格。缩进包含在页面宽度中。
.FT [off | on]这用于打开和关闭格式。如果命令出现&#34; off&#34;,则命令下面的所有文本直到下一个&#34; .FT&#34;命令输出而不进行格式化。如果出现&#34; on&#34;,那么命令下面的所有文字都会到达下一个&#34; .FT&#34;命令输出的字数与填充给定的页面宽度
一样多.LS(linespacing)如果&#34; linespacing&#34;不为零(0),则在每个文本行之间会出现行间距空白行。输入文件中的空白行被视为与文本行相同。
此外,每个命令都会在文本
中拥有它自己的行我真的很感激这方面的帮助。
答案 0 :(得分:1)
这种问题必须分成小问题才能轻松解决。
每行读取输入文件行
一个。如果是格式化命令,请使用格式化选项
更改程序的状态湾否则将正确格式化的行打印到临时文件
使用临时文件的内容覆盖输入文件。
首先,让我们定义一些稍后会重用的类型。如果您是C新手,我邀请您查看this page并阅读"year":2016, "month":10, "day":2
,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
在C中,没有标准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;
功能。但是,使用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], '\0', 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] != '\0' &&
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] == '\0')
{
free(buf);
buf = NULL;
(* s) = 0;
}
else
{
(* s) = strlen(buf);
}
return buf;
}
是定义缓冲区典型大小的宏。此功能需要包含BUFF_SIZE
,因为它使用string.h
和memset
才能使用stdlib.h
。
鉴于此功能,您可以轻松编写另一个将每行读取文件行的文件行,并填充作为输入传递的realloc
结构,如果文件结束已返回,则返回等于零的整数达到。
Line
现在,你差不多完成了。在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] = '\0'; // 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
时将停止的主循环中,您可以根据收到的命令设置一些变量,当您收到常规行时,您可以调用一个格式函数输出在流中按原样格式化的行。这是一个这样的功能的例子。
0
我之前谈过的临时文件可以使用tmpfile
功能打开。当您到达输入文件的末尾时,您只需关闭输入文件并将临时文件的内容复制到其中。只需使用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);
}
}
和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.