【问题描述】
编写一程序模拟文本编辑操作。首先从标准输入读取一行字符串(字符个数不超过512),该行字符串是已经过n(大于0,小于等于10)步编辑操作后的结果。然后从下一行读取n,以及已发生过的n步编辑操作,编辑操作分行输入,输入格式为:
op pos str
其中op为编辑操作命令编码(在此只有插入和删除操作,1表示插入或2表示删除操作);pos表示插入或删除的位置;str表示已经插入或删除的字符串(中间没有空格)。各数据间以一个空格分隔。
然后在空一行后,再分行输入当前将要进行的编辑操作,包括如下四种操作(操作编码分别为:1表示插入,2表示删除操作,3表示撤销(即undo操作),-1表示结束):
1 pos str
表示将在pos位置插入字符串str(中间没有空格),各数据间以一个空格分隔;
2 pos n
表示将从pos位置开始删除n个字符(各数据间以一个空格分隔),若要删除的字符个数多于已有字符个数(即在文本中从pos开始的字符个数小于n),则按实际字符数删除即可。(提示:为了能够撤销删除操作,应按“2 pos str”形式保存命令。)
3
表示撤销最近执行的插入或删除操作,可以进行多次撤销操作,注意:也可以撤销之前已经发生过的n步编辑操作中的操作。
-1
表示退出编辑操作,在屏幕上输出最终编辑后的文本。
要求:
1、上述所有输入的编辑操作中的字符串str都不包含空白字符(空格符、制表符或换行符);
2、插入操作中的位置pos大于等于0,并且小于等于当前文本的字符个数;0位置表示文本第一个字符的位置;若pos为当前文本的字符个数,则表示在文本最后插入字符串;
3、删除操作中的位置pos大于等于0,并且小于当前文字的字符个数;
4、若已无操作可撤销,则再进行撤销操作无效;
5、文本在编辑过程中,总字符个数不会超过512。
【输入形式】
先从键盘输入一行字符串,表示已经经过n步编辑操作后的文本串,然后在下一行输入一个正整数n,并分行输入n步插入或删除操作(表示按时间先后顺序已进行的操作),格式如上所述。随后空一行,再分行输入将要进行的编辑操作,格式如上所述。直到输入-1操作为止。
【输出形式】
在屏幕上输出最终编辑后的文本内容。
【样例输入】
A Stack is a container of objects that are inserted and removed according to the last-in first-out (LIFO) principle.???
4
1 20 ainer
2 0 ???
1 85 -
1 99 (LIFO)
3
2 110 10
1 110 Objects
2 98 1
2 0 1
2 108 10
3
3
3
-1
【样例输出】
A Stack is a container of objects that are inserted and removed according to the last-in first-out principle.Objects
【样例说明】
第一行输入的文本串是先后经过下面4次编辑操作后得到的:先在20位置插入了字符串ainer,然后删除了开始位置的字符串???,随后在85位置插入了一个字符-,最后在99位置插入了字符串(LIFO)。
随后输入了撤销操作,即撤销先前最后进行的“1 99 (LIFO)”操作,也就是将99位置的6个字符删除;
2 110 10:将文本串最后的字符串???删除;
1 110 Objects:在文本串末尾插入字符串Objects;
随后执行了三次删除操作,又执行了三次撤销操作,最后输入的-1表示编辑操作结束,在屏幕上输出最终编辑后的文本串。
#include <stdio.h>
#include <malloc.h>
#include <string.h>
typedef struct node{
int op;
int pos;
int len;
char str[513];
struct node *llink;
struct node *rlink;
}x,*STLink;
void cal(int op,int pos,char str[],char arr[])
{
char s[513];
int len;
len=strlen(str);
if(op==1)
{
strncpy(s,arr,pos);
s[pos]='\0';
strcat(s,str);
strcat(s,(arr+pos));
strcpy(arr,s);
}
else
{
while(arr[pos+len]!='\0')
{
arr[pos]=arr[pos+len];
pos++;
}
arr[pos]='\0';
}
}
void del(int pos,int len,char arr[])
{
int n;
n=strlen(arr);
if((pos+len)>=n)
{//要删除的长度大于等于剩余字符长度
arr[pos]='\0';
}
else
{
while(arr[pos+len]!='\0')
{
arr[pos]=arr[pos+len];
pos++;
}
arr[pos]='\0';
}
}
int main()
{
x pre[10];//打算从下标为1开始存
char arr[513];
int n,i,top_pre;
gets(arr);
scanf("%d",&n);
top_pre=n;
for(i=1;i<=n;i++)
{
scanf("%d %d %s",&pre[i].op,&pre[i].pos,pre[i].str);
}
STLink top_p=NULL,p=NULL;
while(1)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
else if(i!=3)
{//入栈
if(!(p=(STLink)malloc(sizeof(x))))
{
return 1;
}
p->op=i;
if(i==1)
{
scanf("%d %s",&p->pos,p->str);
}
else if(i==2)
{
scanf("%d %d",&p->pos,&p->len);
}
if(top_p==NULL)
{
p->rlink=NULL;//循环链表最右边
}
else
{
p->rlink=top_p;
top_p->llink=p;
}
top_p=p;
}
else{
if(top_p==NULL&&top_pre!=0)
{//数组出栈
top_pre--;
}
else if(top_p!=NULL)
{//链表出栈,向右
p=top_p;
top_p=top_p->rlink;
free(p);
p=NULL;
}
}
}
if(top_p!=NULL)
{
top_p->llink=NULL;//循环链表最左边
}
while(top_pre<n)//while当作判断条件,必须先对top_pre进行判断
{//复原操作,要以n为下标,虽然出栈了,但实际还存着。
if(pre[n].op==1)
{
cal(2,pre[n].pos,pre[n].str,arr);
}
else
{
cal(1,pre[n].pos,pre[n].str,arr);
}
n--;
}
if(top_p!=NULL)
{
while(top_p->rlink!=NULL)//!!!!!这个top_p有可能是NULL
{
top_p=top_p->rlink;//应该从栈底开始操作
}
}
while(top_p!=NULL)
{
if(top_p->op==1)
{
cal(top_p->op,top_p->pos,top_p->str,arr);
}
else
{
del(top_p->pos,top_p->len,arr);
}
p=top_p;
top_p=top_p->llink;
free(p);
p=NULL;
}
printf("%s",arr);
return 0;
}