串操作應用舉例(文本編輯)

// 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

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