资源描述
课程设计实验报告
题目: 编制一个将待格式化的文本按照一定的版面要求重新排版并输出到文件的程序
一:需求分析
Ø 1:文本文件非空且以文本文件形式存放(为空没有格式化意义)。输入输出文件名均由用户从键盘输入。
Ø 2:字的定义:由非(‘@’,‘ ’(空格))的任意ASCII码字符组成。
Ø 3:文本文件的定义:由字母字符,数字字符,空格和可以用ASCII代码显示的字符组成。‘@’只表示换行的意义。‘ ’(空格)只表示一个字的结束的意义。
Ø 4:任何完整的字都没有被分割在两行:,行尾不齐没关系,但要实现左对齐。每行字符数不超过60
Ø 5:输出文件中字与字之间只留一个空格符,即实现多余空格符的压缩。
Ø 6:符号‘@’指示它后面的正文在格式化时应另起一段排放,段首缩入8个字符的位置。
二:概要设计
Ø 1:void printOut()
{ 该函数的功能是:格式化文本文件后必要提示用户的信息说明 }
Ø 2:void writeOut(FILE * fp2,char c1)
{ 该函数的功能是:将字符输出到文本文件和屏幕 }
Ø 3:int zuokongbai(FILE * fp2)
{ 该函数的功能是:实现文本参数格式(左空白) }
Ø 4:void pageNumber(FILE * fp2,char * aIndex,int * page)
{ 该函数的功能是:输出当前页码 }
Ø 5:void out(int * columns,char * array,int * linage,FILE * fp2,int * page,int * size)
{ 该函数的功能是:判断是否输出到文本文件和屏幕 }
Ø 6:void linageFull(FILE * fp2,int * linage,int * columns,int * page)
{ 该函数的功能是:输出页首的格式(头长+左空白) }
Ø 7:void readIn(FILE * fp1,FILE * fp2)
{ 该函数是整个程序的核心,执行程序的主要逻辑判断 }
Ø 8:void main()
{ 该函数的功能是:程序的入口 }
三:详细设计
1,头文件:noteParameter.h(参数的说明)
int (PageLength) = 56; //页长(一页最大的行数)
int PageWedth = 60; //页宽(一行最大的字符数)
int LeftMargin = 10; //左空白(一行开始输出的空格数)
int HeadingLength = 5; //头长(一页开始输出的空行数)
int FootingLength = 5; //脚长(每页最后空5行)
int StaringPageNumber = 1; //起始页号
2,主程序中需要的全局变量和函数声明
int page = 1; //记录页数
int i = 0; //循环变量
char a[5]; //记录page的char类型
char * aIndex = a; //数组a的首地址
//函数声明(后面的函数调用了它)
void linageFull(FILE * fp2,int * linage,int * columns,int * page);
3:主函数和其他函数的伪代码算法
说明:为了便于描述。‘文本文件1’代表用户输入的要格式化的文本文件。‘文本文件2’代表用户输入的格式化之后保存的文本文件。
函数1:
void printOut() //输出头文件中的所有整形变量
{
//这个函数中的参数全部来自头文件
printf("\n");
printf(" 格式化文本文件结束\n");
printf("版面的参数如下:\n");
printf("页长:%d\n",PageLength);
printf("页宽:%d\n",PageWedth);
printf("左空白:%d\n",LeftMargin);
printf("头长:%d\n",HeadingLength);
printf("脚长:%d\n",FootingLength);
printf("起始页号:%d\n",StaringPageNumber);
printf("\n");
printf(" 特别说明:本程序只支持英文格式化,对于中文格式化存在乱码问题。\n");
printf("\n");
}
函数2:
void writeOut(FILE * fp2,char c1) // 输出到文本文件2和屏幕
{
char ch1;
ch1 = fputc(c1,fp2);//接收从文本文件1中读出的一个字符,并且保存到文本文件2中
printf("%c",ch1); //把这个字符输出到外设(屏幕)
}
函数3:
int zuokongbai(FILE * fp2) // 左空白
{
for(i=0; i<10; i++)
writeOut(fp2,' '); //循环10次,输出10个空格到文本文件2中
return i; //返回值为10.它赋给记录单行字节数的变量columns
}
函数4:
void pageNumber(FILE * fp2,char * aIndex,int * page) //输出当前页码
{
int m,n; //定义2个整形变量接收page和page%10的值
m = *page; //接收page的值
i=0;
while(m != 0) //判断条件为:m的值不为0即page的值不为0
{
n = m % 10;
*(aIndex+i) = n+'0'; //对数组a进行赋值操作,把int类型的page的各位数转换为字符型保存到数组a中,以便于向文本文件2中输出page
i++;
m = m /10;
}
//此时page 已经保存在数组a中了,开始输出page
for(i=i-1; i>=0; i--)
{
writeOut(fp2,*(aIndex+i)); //向文本文件2中输出page
}
(*page)++; //指向下一页
}
函数5:
void out(int * columns,char * array,int * linage,FILE * fp2,int * page,int * size) //输出
{
if(((*(columns))+1+strlen(array)) > 60) //判断这一行是否还能够输出空格加一个单词
{
//这一行不能再输出了,开始换行
if((*(linage))>50) //判断这一页是否已经印满
{
linageFull(fp2,linage,columns,page);//转到下一页
for(i=0; i<*(size); i++)
{
writeOut(fp2,*(array+i));//把保存在数组中的一个字输出到文本文件2中
(*(columns))++;//输出一个字符,这一行的字符数就增加一个
}
(*(size)) = 0;//输出之后就开始重新向数组array中读入字符,所以size要归0
(*(array)) ='\0';//如果是多个空格连在一起,那么就需要把array数组第一个设为结束字符。
}
else //这一页还没印满,换行后开始输出
{
writeOut(fp2,'\n');//换行
(*(linage))++;
//*(columns)=0;
(*(columns)) = zuokongbai(fp2); // 左空白10
for(i=0; i<(*(size)); i++)
{
writeOut(fp2,(*(array+i)));//通过循环向文本文件2中输入字
(*(columns))++;
}
(*(size)) = 0;
(*(array)) ='\0';
}
}
else //这一行还没有满,还可以再输出
{
writeOut(fp2,' ');
(*(columns))++;
for(i=0;i<*size; i++)
{
writeOut(fp2,*(array+i));
(*(columns))++;
}
(*(size)) = 0;
(*(array)) ='\0';
}
}
函数6:
void linageFull(FILE * fp2,int * linage,int * columns,int * page) // 开始下一页的打印
{
//完成页的尾部格式(空一行后居中输出页码page再空3行)
writeOut(fp2,'\n'); //空一行
for(i=0; i<29; i++) //居中输出页码
{
writeOut(fp2,' ');
}
pageNumber(fp2,aIndex,page);
for(i=0; i<3; i++)
{
writeOut(fp2,'\n'); //再空3行
}
*linage=0;
//开始打印第二页。实现输出页首的格式(头长+左空白)
for(i=0; i<5; i++) // 头长5
{
writeOut(fp2,'\n');
*linage++; //已经占有linage行
}
*columns = zuokongbai(fp2); // 左空白10
}
函数7:
void readIn(FILE * fp1,FILE * fp2) // 读入文本文件
{
int blankNumber=0; // 记录空格的数量
int linage = 0; // 记录行数
int columns = 0; // 记录单行的字节数
char array[61] = {"\0"};//存一个单词
char * arrayIndex = array;
int size = 0; // 初始化单词的长度
for(i=0; i<5; i++) // 头长5
{
writeOut(fp2,'\n');
linage++; //已经占有linage行
}
columns = zuokongbai(fp2); // 左空白10
for(i=0; i<7; i++) //段首缩进8字节
{
writeOut(fp2,' ');
columns++;
}
//以上代码实现了基本的版面参数要求,下面开始具体到字母的排版
char c1;
c1 = fgetc(fp1);//读入第一个字符
while(c1!=EOF)//如果读到结尾了,退出这个函数。否则开始字符的输入输出操作
{
if(c1==' ')//如果字符为空格
{
if(strlen(array)==0)//判断空格前是否有一个字
; //没有字不打印
else//有一个字
{
//调用这个函数把这个字输出到文本文件2和屏幕中
out(&columns,array,&linage,fp2,&page,&size);
}
}
else if(c1=='@') //如果字符为‘@’就要另起一段
{
//先输出
if(strlen(array)==0) //判断‘@’前是否有一个字
; //没有字不打印
else//有字要打印
{
//调用这个函数把这个字输出到文本文件2和屏幕中
out(&columns,array,&linage,fp2,&page,&size);
}
//输出字后开始另起下一段
if(linage>50) //判断这一页是否已经印满
{
//印满了要换页输出
linageFull(fp2,&linage,&columns,&page);
for(i=0; i<7; i++) //段首缩进8字节
{
writeOut(fp2,' ');
columns++;
}
}
Else//这一页没有印满
{
writeOut(fp2,'\n');//换行
linage++;
columns=0;
columns = zuokongbai(fp2); // 左空白10
for(i=0; i<7; i++) //段首缩进8字节
{
writeOut(fp2,' ');
columns++;
}
}
}
else //此时c1是一个要输出的字符
{
array[size] = c1;//保存到数组中
size++;
array[size]='\0';
}
c1 = fgetc(fp1);//上一个字符处理完了,开始从文本文件1中读出下一个字符
if(c1 == EOF)//首先判断是不是结束了
{
//文本文件已经读完。把前面已经读出保存在数组中的字输出到文本文件2中
out(&columns,array,&linage,fp2,&page,&size);
break;//结束while循环
}
if(strlen(array) >61)//程序中设计一个字不能超过60个字符,这里判断条件为61是加了一个结束符‘\0’.
{
printf("字符格式错误!哪有这么长的单词!\n");
break; //结束while循环
}
}
}
函数8:
//程序的入口
void main()
{
FILE * fp1,* fp2; // fp1指向读入的文本文件,fp2指向输出的文本文件
char fileName_one[100]; // 保存要格式化文本文件的文件名
char fileName_two[100]; // 保存格式化之后输出文本文件的文件名
printf("请输入要格式化文件的文件名(包括后缀名):\n");
gets(fileName_one);
if((fp1=fopen(fileName_one,"r"))==NULL)
{
printf("The file \"%s\" was not fopen!\n",fileName_one);
exit(0);
}
//得到要进行格式化的文本文件1的地址
printf("请输入输出文件的文件名(包括后缀名):\n");
gets(fileName_two);
if((fp2=fopen(fileName_two,"a"))==NULL)
{
printf("The file \"%s\" was not fopen!\n",fileName_two);
exit(0);
}
//得到格式化后要保存到文本文件2的地址
readIn(fp1,fp2); // 读入文本文件开始格式化
printOut(); // 参数说明
fclose(fp1); // 关闭文件(把文件缓冲区的数据送入硬盘中)
fclose(fp2); // 关闭文件(把文件缓冲区的数据送入硬盘中)
}
四:调试分析
Ø 1:本程序历时9天完工,在分析数据结构时对程序的架构没有想好,导致这个程序有2个版本。每个版本都有各自的优点和缺点。现在程序已经实现了所有的功能并对代码进行了必要的优化设计。
Ø 2:在编程过程中,对设计做了如下修改:
l (1):在第一版中设计为:读一个字符判断是否为:空,‘@’。(占不考虑其他条件)不是就直接输出。导致不能实现任何完整的字都没有被分割在两行这个功能。
l (2)在第二版中改为:读一个字符判断是否为:空字符,‘@’。(占不考虑其他条件)不是就保存在数组中,这个数组就是保存一个字的作用。判断输出就是一个一个字的输出,这样就实现了任何完整的字都没有被分割在两行这个功能。
l (3):在第一版中就遇到页码输出的问题。开始我设计页码是整形,当格式化文本文件过大时,页码输出就出现了问题。实现输出页码是用fputc这个函数,它是实现字符的输出,就把整形的页码数转换为ASCII码形式输出了。
l (4)在第二版中改为:把整形的页码转换为字符型用一个字符数组来保存。
每次输出页码是就是输出这个数组中的数据。这样就实现了页码的完整输出。
五:用户手册
Ø 1:本程序的运行环境为DOS操作系统,执行文件为:文本格式化.exe。
Ø 2:进入程序后即显示提示信息:请输入要格式化文件的文件名(包括后缀名):以等待用户输入待格式化的文本文件名(一个回车为结束标志的字符串),如果该文件不存在,则显示信息:The file “?” was not fopen!(?为用户输入的文件名)并退出程序。
如果该文件存在,则执行程序的下一步。提示信息:请输入输出文件的文件名(包括后缀名): 以等待用户输入输出文件的文本文件名(一个回车为结束标志的字符串),如果该文件不存在,则程序自动新建一个,如果新建失败则提示信息:The file “?” was not fopen!(?为用户输入的文件名)并退出程序。如果该文件存在,则在该文件后面追加。
Ø 3:输入结束后,程序即进行格式化。随后输出格式化信息。按任意键退出。详细见测试结果。
Ø 4:格式化结果保存在由用户指定的文本文件中,如果该文件存在,则在该文件后面追加。(为了更好的观察测试结果,请确保当前工程中没有该文件)
Ø 5:测试数据最大字不能超过60个字符。
Ø 6:本程序只格式化由字母字符构成的文本文件。对于中文格式化存在乱码问题。
六:测试结果
Ø 1:测试数据:I have a dream.txt文本文件 《I have a dream》节选
I say to you today, my friends, that in spite of the difficulties and frustrations of the moment, I still have a dream. It is a dream deeply rooted in the American dream.@I have a dream that one day this nation will rise up and live out the true meaning of its creed: "We hold these truths to be self-evident: that all men are created equal."@I have a dream that one day on the red hills of Georgia the sons of former slaves and the sons of former slaveowners will be able to sit down together at a table of brotherhood.@I have a dream that one day even the state of Mississippi, a desert state, sweltering with the heat of injustice and oppression, will be transformed into an oasis of freedom and justice.@I have a dream that my four children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character.@I have a dream today.
Ø 2:测试结果:
请输入要格式化文件的文件名(包括后缀名):
i have a dream.txt
请输入输出文件的文件名(包括后缀名):
value.txt
I say to you today, my friends, that in
spite of the difficulties and frustrations of the
moment, I still have a dream. It is a dream deeply
rooted in the American dream.
I have a dream that one day this nation
will rise up and live out the true meaning of its
creed: "We hold these truths to be self-evident:
that all men are created equal."
I have a dream that one day on the red
hills of Georgia the sons of former slaves and the
sons of former slaveowners will be able to sit
down together at a table of brotherhood.
I have a dream that one day even the state
of Mississippi, a desert state, sweltering with
the heat of injustice and oppression, will be
transformed into an oasis of freedom and justice.
I have a dream that my four children will
one day live in a nation where they will not be
judged by the color of their skin but by the
content of their character.
I have a dream today.
格式化文本文件结束
版面的参数如下:
页长:56
页宽:60
左空白:10
头长:5
脚长:5
起始页号:1
特别说明:本程序只支持英文格式化,对于中文格式化存在乱码问题。
Press any key to continue
Ø 3:为了节省篇幅,其他测试数据没有列出。请参考程序执行结果。
七:附录
1:源程序文件名清单:
noteParameter.h //参数说明
note.cpp //主程序
2:由于文字编辑软件的格式问题,此报告打印的测试数据与程序运行的数据会有所出入,请以程序执行结果的数据为准。
3:另附全部源代码。
展开阅读全文