串操作应用举例(文本编辑)

// algo4-2.cpp 文本行编辑
#include"c1.h"
#include"c4-2.h" // 采用串的堆分配存储结构
#include"bo4-2.cpp" // 串的堆分配基本操作
#define MAX_LEN 25 // 文件最大行数
#define LINE_LEN 75 // 每行字符数最大值+1
#define NAME_LEN 20 // 文件名最大长度(包括盘符、路径)+1
// 全局变量(见图4.12)
HString T[MAX_LEN];
char str[LINE_LEN],filename[NAME_LEN]="";
FILE *fp;
int n=0; // 文本行数
void Open()
{ // 打开文件(新或旧)
	if(filename[0]) // 文件已打开
		printf("已存在打开的文件\n");
	else
	{
		printf("请输入文件名(可包括盘符、路径,不超过%d个字符): ",NAME_LEN-1);
		scanf("%s",filename);
		fp=fopen(filename,"r"); // 以读的方式打开文件
		if(fp) // 已存在此文件
		{
			while(fgets(str,LINE_LEN,fp)) // 由文件读入1行字符成功
			{
				str[strlen(str)-1]=0; // 将换行符10强制改为串结束符0
				if(n>=MAX_LEN)
				{
					printf("文件太大\n");
					return;
				}
				StrAssign(T[n],str);
				n++;
			}
			fclose(fp); // 关闭文件
		}
		else
			printf("新文件\n");
	}
}
void List()
{ // 显示文本内容
	int i;
	for(i=0;i<n;i++)
	{
		printf("%d: ",i+1);
		StrPrint(T[i]);
	}
}
void Insert()
{ // 插入行
	int i,l,m;
	printf("在第l行前插m行,请输入l m: ");
	scanf("%d%d%*c",&l,&m);
	if(n+m>MAX_LEN)
	{
		printf("插入行太多\n");
		return;
	}
	if(n>=l-1&&l>0)
	{
		for(i=n-1;i>=l-1;i--)
			T[i+m]=T[i];
		n+=m;
		printf("请顺序输入待插入内容:\n");
		for(i=l-1;i<l-1+m;i++)
		{
			gets(str);
			InitString(T[i]);
			StrAssign(T[i],str);
		}
	}
	else
		printf("行超出范围\n");
}
void Delete()
{ // 删除行
	int i,l,m;
	printf("从第l行起删除m行,请输入l m: ");
	scanf("%d%d",&l,&m);
	if(n>=l+m-1&&l>0)
	{
		for(i=l-1+m;i<n;i++)
		{
			free(T[i-m].ch);
			T[i-m]=T[i];
		}
		for(i=n-m;i<n;i++)
			InitString(T[i]);
		n-=m;
	}
	else
		printf("行超出范围\n");
}
void Copy()
{ // 拷贝行
	int i,l,m,k;
	printf("把第l行开始的m行插在原k行之前,请输入l m k: ");
	scanf("%d%d%d",&l,&m,&k);
	if(n+m>MAX_LEN)
	{
		printf("拷贝行太多\n");
		return;
	}
	if(n>=k-1&&n>=l-1+m&&(k>=l+m||k<=l))
	{
		for(i=n-1;i>=k-1;i--)
			T[i+m]=T[i];
		n+=m;
		if(k<=l)
			l+=m;
		for(i=l-1;i<l-1+m;i++)
		{
			InitString(T[i+k-l]);
			StrCopy(T[i+k-l],T[i]);
		}
	}
	else
		printf("行超出范围\n");
}
void Modify()
{ // 修改行
	int i;
	printf("请输入待修改的行号: ");
	scanf("%d%*c",&i);
	if(i>0&&i<=n) // 行号合法
	{
		printf("%d: ",i);
		StrPrint(T[i-1]);
		printf("请输入新内容: ");
		gets(str);
		StrAssign(T[i-1],str);
	}
	else
		printf("行号超出范围\n");
}
void Search()
{ // 查找字符串
	int i,k,f=1; // f为继续查找标志
	char b[2];
	HString s;
	printf("请输入待查找的字符串: ");
	scanf("%s%*c",str);
	InitString(s);
	StrAssign(s,str);
	for(i=0;i<n&&f;i++) // 逐行查找
	{
		k=1; // 由每行第1个字符起查找
		while(k)
		{
			k=Index(T[i],s,k); // 由本行的第k个字符开始查找
			if(k) // 找到
			{
				printf("第%d行: ",i+1);
				StrPrint(T[i]);
				printf("第%d个字符处找到。继续查找吗(Y/N)? ",k);
				gets(b);
				if(b[0]!='Y'&&b[0]!='y') // 中断查找
				{
					f=0;
					break;
				}
				else
					k++;
			}
		}
	}
	if(f)
		printf("没找到\n");
}
void Replace()
{ // 替换字符串
	int i,k,f=1; // f为继续替换标志
	char b[2];
	HString s,t;
	printf("请输入待替换的字符串: ");
	scanf("%s%*c",str);
	InitString(s);
	StrAssign(s,str);
	printf("替换为");
	scanf("%s%*c",str);
	InitString(t);
	StrAssign(t,str);
	for(i=0;i<n&&f;i++) // 逐行查找、替换
	{
		k=1; // 由每行第1个字符起查找
		while(k)
		{
			k=Index(T[i],s,k); // 由本行的第k个字符开始查找
			if(k) // 找到
			{
				printf("第%d行: ",i+1);
				StrPrint(T[i]);
				printf("第%d个字符处找到。是否替换(Y/N)? ",k);
				gets(b);
				if(b[0]== 'Y'||b[0]== 'y')
				{
					StrDelete(T[i],k,StrLength(s));
					StrInsert(T[i],k,t);
				}
				printf("继续替换吗(Y/N)?");
				gets(b);
				if(b[0]!= 'Y' &&b[0]!= 'y') // 中断查找、替换
				{
					f=0;
					break;
				}
				else
					k+=StrLength(t);
			}
		}
	}
	if(f)
		printf("没找到\n");
}
void Save()
{ // 存盘
	int i,j;
	fp=fopen(filename,"w"); // 以写的方式重新打开文件
	if(fp) // 打开文件成功
	{
		for(i=0;i<n;i++)
		{ // 依次将每行存入文件
			for(j=0;j<T[i].length;j++) // 依次存入每个字符
				fputc(T[i].ch[j],fp);
			fputc(10,fp); // 存入换行符
			ClearString(T[i]); // 释放串空间
		}
		fclose(fp); // 关闭文件
	}
	else
		printf("存盘失败\n");
}
void main()
{
	Status s=TRUE;
	int i,k;
	for(i=0;i<MAX_LEN;i++) // 初始化串
		InitString(T[i]);
	while(s)
	{
		printf("请选择: 1.打开文件(新或旧) 2.显示文件内容\n");
		printf(" 3.插入行4.删除行5.拷贝行6.修改行\n");
		printf(" 7.查找字符串8.替换字符串\n");
		printf(" 9.存盘退出0.放弃编辑\n");
		scanf("%d",&k);
		switch(k)
		{
		case 1: Open();
			break;
		case 2: List();
			break;
		case 3: Insert();
			break;
		case 4: Delete();
			break;
		case 5: Copy();
			break;
		case 6: Modify();
			break;
		case 7: Search();
			break;
		case 8: Replace();
			break;
		case 9: Save();
		case 0: s=FALSE;
		}
	}
}

代码的运行结果:


algo4-3.cpp 是以教科书图4.9 为例建立书名关键词索引表的程序。教科书图4.9(a)
所示的书目文件存于BookInfo.txt 中,其内容如下:

005 Computer Data Structures
010 Introduction to Data Structures
023 Fundamentals of Data Structures
034 The Design and Analysis of Computer Algorithms
050 Introduction to Numerical Analysis
067 Numerical Analysis

程序首先将存于BookInfo.txt 文件中的每种书的书号及书名中的关键词提取出来。书
号存储于整型变量BookNo 中,书名中的每个关键词先临时存储于全局变量wdlist 中,
wdlist 的结构如图413 所示。
在提取书名的关键词时,要注意剔除the、a、of 等非索引词。这些词在书名中一般是
小写,对于首字母是小写的单词不作处理即可。但这些非索引词若是书名的第1 个单词,
则首字母也为大写。为了解决这个问题,将非索引词存入文件NoIdx.txt 中,内容如下:

5A
An
In
Of
The

NoIdx.txt 文件的内容可通过文字编辑软件自行输入。第1 行为非索引词个数,单词按
字典顺序排列。程序将文件NoIdx.txt 的内容读入全局变量noidx 中。noidx 的结构和
wdlist 相同,其内容如图414 所示。对于书名中的每个单词,首先检索是否出现在noidx
中,如果是,则不将该单词插入wdlist 中作为关键词。图413 在显示wdlist 结构的同时
也显示了wdlist 存储书目文件第4 本书(书号为34)时的内容。


程序依次根据临时存储于wdlist 中的每个书名的关键词,产生和充实关键词索引表。
方法是:首先建一个空的关键词索引表变量idxlist,然后依次查询wdlist 中的各个关键词
是否存在于idxlist 中。如果已存在,则仅把该关键词的书号按升序插入相应的链表中。否

则先按字母顺序将wdlist 中的关键词插入idxlist,再插入书号。idxlist 的结构及内容如图
415 所示。


书名关键词索引表仅在增加新书时有变化,因此不必在每次检索书名时都建立一次。
可以把algo4-3.cpp 生成的书名关键词索引表(idxlist)存成文件(BookIdx.txt),由索引查询
图书的程序algo4-4.cpp 调用。algo4-3.cpp 程序运行的结果就是生成BookIdx.txt 文件,
其内容如下:

9
Algorithms
1
34
Analysis
3
34 50 67
Computer

2

5 34

Data

3

5 10 23

Design
1
34
Fundamentals
1
23
Introduction
2
10 50
Numerical
2
50 67
Structures
3

5 10 23

// algo4-3.cpp 根据书目文件bookinfo.txt生成书名关键词索引文件bookidx.txt,
// 为运行algo4-4.cpp做准备,算法4.9~4.14
#include"c1.h"
typedef int ElemType;
#include"c2-5.h"
#include"bo2-6.cpp"
#include"c4-2.h"
#include"bo4-2.cpp"
#define MaxKeyNum 25 // 索引表的最大容量(关键词的最大数目)
#define MaxLineLen 52 // 书目串(书目文件的1行)buf的最大长度
#define MaxNoIdx 10 // 非索引词(也是一个书目中关键词)的最大数目
struct WordListType // 一个书目的词表(顺序表)和非索引词表(有序表)共用类型
{
	char *item[MaxNoIdx]; // 词表(字符串)指针数组
	int last; // 词的数量
};
struct IdxTermType // 索引项类型
{
	HString key; // 关键词(堆分配类型,c4-2.h)
	LinkList bnolist; // 存放书号索引的链表(c2-5.h)
};
struct IdxListType // 索引表类型(有序表)
{
	IdxTermType item[MaxKeyNum+1]; // 索引项数组类型
	int last; // 关键词的个数
};
// 全局变量
char buf[MaxLineLen+1]; // 当前书目串(包括’\0’)
WordListType wdlist,noidx; // 暂存一种书的词表,非索引词表
void InitIdxList(IdxListType &idxlist)
{ // 初始化操作,置索引表idxlist为空表,且在idxlist.item[0]设一空串
	idxlist.last=0;
	InitString(idxlist.item[0].key); // 初始化[0]单元,函数在bo4-2.cpp中
	InitList(idxlist.item[0].bnolist); // 初始化[0]单元,函数在bo2-6.cpp中
}
void ExtractKeyWord(int &BookNo)
{ // 从buf中提取书名关键词到词表wdlist,书号存入BookNo
	int i,l,f=1; // f是字符串buf结束标志0:结束1:未结束
	char *s1,*s2;
	for(i=1;i<=wdlist.last;i++)
	{ // 释放上一个书目在词表wdlist的存储空间
		free(wdlist.item[i]);
		wdlist.item[i]=NULL;
	}
	wdlist.last=0; // 初始化词表wdlist的词数量
	BookNo=atoi(buf); // 将前几位数字转化为整数,赋给书号BookNo
	s1=&buf[4]; // s1指向书名的首字符
	while(f)
	{ // 提取书名关键词到词表wdlist
		s2=strchr(s1,' '); // s2指向s1后的第一个空格,如没有,返回NULL
		if(!s2) // 到串尾(没空格)
		{
			s2=strchr(s1,'\12'); // s2指向buf的最后一个字符(回车符10)
			f=0;
		}
		l=s2-s1; // 单词长度
		if(s1[0]>= 'A'&&s1[0]<='Z') // 单词首字母为大写
		{ // 写入词表
			wdlist.item[wdlist.last]=(char *)malloc((l+1)*sizeof(char)); // 生成串空间(包括'\0')
			for(i=0;i<l;i++)
				wdlist.item[wdlist.last][i]=s1[i]; // 写入词表
			wdlist.item[wdlist.last][l]=0; // 串结束符
			for(i=0;i<noidx.last&&(l=strcmp(wdlist.item[wdlist.last],noidx.item[i]))>0;i++);
			// 查找是否为非索引词
			if(!l) // 是非索引词
			{
				free(wdlist.item[wdlist.last]); // 从词表中删除该词
				wdlist.item[wdlist.last]=NULL;
			}
			else
				wdlist.last++; // 词表长度+1
		}
		s1=s2+1; // s1移动到下一个单词的首字符处
	};
}
void GetWord(int i,HString &wd)
{ // 用wd返回词表wdlist中第i个关键词,算法4.11
	StrAssign(wd,wdlist.item[i]); // 生成关键字字符串bo4-2.cpp
}
int Locate(IdxListType &idxlist,HString wd,Status &b)
{ // 在索引表idxlist中查询是否存在与wd相等的关键词。若存在,则返回其
	// 在索引表中的位置,且b取值TRUE;否则返回插入位置,且b取值FALSE,算法4.12
	int i,m;
	for(i=idxlist.last;(m=StrCompare(idxlist.item[i].key,wd))>0;--i); // bo4-2.cpp
	if(m==0) // 找到
	{
		b=TRUE;
		return i;
	}
	else
	{
		b=FALSE;
		return i+1;
	}
}
void InsertNewKey(IdxListType &idxlist,int i,HString wd)
{ // 在索引表idxlist的第i项上插入新关键词wd,并初始化书号索引的链表为空表,算法4.13
	int j;
	for(j=idxlist.last;j>=i;--j) // 后移索引项
		idxlist.item[j+1]=idxlist.item[j];
	InitString(idxlist.item[i].key); // bo4-2.cpp
	StrCopy(idxlist.item[i].key,wd); // 串拷贝插入新的索引项bo4-2.cpp
	InitList(idxlist.item[i].bnolist); // 初始化书号索引表为空表bo2-6.cpp
	idxlist.last++;
}
void InsertBook(IdxListType &idxlist,int i,int bno)
{ // 在索引表idxlist的第i项中插入书号为bno的索引,算法4.14
	Link p;
	MakeNode(p,bno); // 分配结点bo2-6.cpp
	p->next=NULL;
	Append(idxlist.item[i].bnolist,p); // 插入新的书号索引bo2-6.cpp
}
void InsIdxList(IdxListType &idxlist,int bno)
{ // 将书号为bno的关键词插入索引表,算法4.10
	int i,j;
	Status b;
	HString wd;
	InitString(wd); // bo4-2.cpp
	for(i=0;i<wdlist.last;i++)
	{
		GetWord(i,wd);
		j=Locate(idxlist,wd,b); // 关键词的位置或待插入的位置(当索引表中不存在该词)
		if(!b) // 索引表中不存在关键词wd
			InsertNewKey(idxlist,j,wd); // 在索引表中插入新的索引项
		InsertBook(idxlist,j,bno); // 插入书号索引
	}
}
void PutText(FILE *f,IdxListType idxlist)
{ // 将生成的索引表idxlist输出到文件f
	int i,j;
	Link p;
	fprintf(f,"%d\n",idxlist.last);
	for(i=1;i<=idxlist.last;i++)
	{
		for(j=0;j<idxlist.item[i].key.length;j++)
			fprintf(f,"%c",idxlist.item[i].key.ch[j]); // HString类型串尾没有\0,只能逐个字符输出
		fprintf(f,"\n%d\n",idxlist.item[i].bnolist.len);
		p=idxlist.item[i].bnolist.head;
		for(j=1;j<=idxlist.item[i].bnolist.len;j++)
		{
			p=p->next;
			fprintf(f,"%d ",p->data);
		}
		fprintf(f,"\n");
	}
}
void main()
{ // 算法4.9
	FILE *f; // 任何时间最多打开一个文件
	IdxListType idxlist; // 索引表
	int BookNo; // 书号变量
	int k;
	if(!(f=fopen("NoIdx.txt","r"))) // 打开非索引词文件
		exit(OVERFLOW);
	fscanf(f,"%d",&noidx.last); // 读取非索引词个数
	for(k=0;k<noidx.last;k++) // 把非索引词文件的内容依次拷到noidx中
	{
		fscanf(f,"%s",buf);
		noidx.item[k]=(char*)malloc((strlen(buf)+1)*sizeof(char));
		strcpy(noidx.item[k],buf);
	}
	fclose(f); // 关闭非索引词文件
	if(!(f=fopen("BookInfo.txt","r"))) // 打开书目文件
		exit(FALSE);
	InitIdxList(idxlist); // 设索引表idxlist为空,并初始化[0]单元
	while(fgets(buf,MaxLineLen,f)) // 由书目文件读取1行信息到buf成功
	{
		ExtractKeyWord(BookNo);//将buf中的书号存入BookNo,关键词提取到词表(当前书目的关键词表)中
		InsIdxList(idxlist,BookNo); // 将书号为BookNo的关键词及书号插入索引表idxlist中
	}
	fclose(f); // 关闭书目文件
	if(!(f=fopen("BookIdx.txt","w"))) // 打开书名关键词索引文件
		exit(INFEASIBLE);
	PutText(f,idxlist); // 将生成的索引表idxlist输出到书名关键词索引文件
	fclose(f); // 关闭书名关键词索引文件
}

程序运行结果:生成BookIdx.txt 文件。
algo4-4.cpp 根据algo4-3.cpp 产生的文件BookIdx.txt 索引查询图书。首先将存有书
名关键词索引表信息的文件BookIdx.txt 的内容恢复到变量idxlist(见图415)中。为方便
查询,将关键词一律存为小写。再将书目文件BookInfo.txt 的内容存入到变量booklist(见
图416)中。程序运行时,从键盘输入一个书名关键词,并将此单词转为小写,在idxlist
中查找。如果找到,则根据相应的链表中所存储的书号,依次查询booklist 并输出相应的
书名。

// algo4-4.cpp 根据algo4-3.cpp产生的文件,索引查询图书
#include"c1.h"
typedef int ElemType;
#include"c2-5.h"
#include"bo2-6.cpp"
#include"c4-2.h"
#include"bo4-2.cpp"
#define MaxBookNum 10
// 假设只对10个书名建索引表
#define MaxKeyNum 25
// 索引表的最大容量(关键词的最大数目)
#define MaxLineLen 46 // 书名的最大长度
struct IdxTermType // 索引项类型
{
	HString key; // 关键词(堆分配类型,c4-2.h)
	LinkList bnolist; // 存放书号索引的链表(c2-5.h)
};
struct IdxListType // 索引表类型(有序表)
{
	IdxTermType item[MaxKeyNum+1]; // 索引项数组类型
	int last; // 关键词的个数
};
struct BookTermType // 书目项类型
{
	char bookname[MaxLineLen+1]; // 书名串(包括′\0′)
	int bookno; // 书号
};
struct BookListType // 书目表类型(有序表)
{
	BookTermType item[MaxBookNum]; // 书目项数组类型
	int last; // 书目的数量
};
void main()
{
	FILE *f; // 任何时间最多打开一个文件
	IdxListType idxlist; // 索引表
	BookListType booklist; // 书目表
	char buf[MaxLineLen+5]; // 当前书目串(包括书号和’\0’)
	HString ch; // 索引字符串
	int BookNo; // 书号
	Link p; // 链表指针
	int i,j,k,flag=1; // flag是继续查询的标志
	InitString(ch); // 初始化HString类型的变量
	if(!(f=fopen("BookIdx.txt","r"))) // 打开书名关键词索引表文件
		exit(OVERFLOW);
	fscanf(f,"%d",&idxlist.last); // 书名关键词个数
	for(k=0;k<idxlist.last;k++) // 把关键词文件的内容拷到idxlist中
	{
		fscanf(f,"%s",buf);
		i=0;
		while(buf[i])
			buf[i++]=tolower(buf[i]); // 字母转为小写
		InitString(idxlist.item[k].key);
		StrAssign(idxlist.item[k].key,buf);
		InitList(idxlist.item[k].bnolist); // 初始化书号链表,bo2-6.cpp
		fscanf(f,"%d",&i);
		for(j=0;j<i;j++)
		{
			fscanf(f,"%d",&BookNo);
			MakeNode(p,BookNo); // 产生新的书号结点,bo2-6.cpp
			p->next=NULL; // 给书号结点的指针域赋值
			Append(idxlist.item[k].bnolist,p); // 在表尾插入新的书号结点,bo2-6.cpp
		}
	}
	fclose(f);
	if(!(f=fopen("BookInfo.txt","r"))) // 打开书目文件
		exit(FALSE);
	i=0;
	while(fgets(buf,MaxLineLen,f))
	{ // 把书目文件的内容拷到booklist中
		booklist.item[i].bookno=atoi(buf); // 前几位数字为书号
		strcpy(booklist.item[i++].bookname,&buf[4]); // 将buf由书名开始的字符串拷贝到booklist中
	}
	booklist.last=i;
	while(flag)
	{
		printf("请输入书目的关键词(一个):");
		scanf("%s",buf);
		i=0;
		while(buf[i])
			buf[i++]=tolower(buf[i]); // 字母转为小写
		StrAssign(ch,buf);
		i=0;
		do
		{
			k=StrCompare(ch,idxlist.item[i++].key); // bo4-2.cpp
		}while(k&&i<=idxlist.last);
		if(!k) // 索引表中有此关键词
		{
			p=idxlist.item[--i].bnolist.head->next; // p指向索引表中此关键词相应链表的首元结点
			while(p)
			{
				j=0;
				while(j<booklist.last&&p->data!=booklist.item[j].bookno) //在booklist中找相应的书号
					j++;
				if(j<booklist.last)
					printf("%3d %s",booklist.item[j].bookno,booklist.item[j].bookname);
				p=p->next; // 继续向后找
			}
		}
		else
			printf("没找到\n");
		printf("继续查找请输入1,退出查找请输入0:");
		scanf("%d",&flag);
	}
}

代码运行的结果:

请输入书目的关键词(一个):DATA
5 Computer Data Structures
10 Introduction to Data Structures
23 Fundamentals of Data Structures
继续查找请输入1,退出查找请输入0:1
请输入书目的关键词(一个):structure
没找到
继续查找请输入1,退出查找请输入0:0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章