简单行编辑程序

实验题目:简单行编辑程序
一,题目:
30、简单行编辑程序
[问题描述]
文本编辑程序是利用计算机进行文字加工的基本软件工具,实现对文本文件的插入、删除等修改操作。限制这些操作以行为单位进行的编辑程序称为行编辑程序。
被编辑的文本文件可能很大,全部读入编辑程序的数据空间(内存)的做法既不经济,
也不总能实现。一种解决方法是逐段地编辑。任何时刻只把待编辑文件的一段放在内存,称为活区。试按照这种方法实现一个简单的行编辑程序。设文件每行不超过 320 个字符,很少超过 80 字符。
[基本要求]
实现以下 4 条基本编辑命令:
(1) 行插入。格式:i<行号><回车><文本><回车>
将<文本>插入活区中第<行号>行之后
(2)行删除。格式:d<行号 1>[□<行号 2>]<回车>
删除活区中第<行号 1>行(到第<行号 2>行)。两种格式的例子是:“d10↙”和“d10□14↙”
(3)活区切换。格式:n<回车>
将活区写入输出文件,并从输入文件中读入下一段,作为新的活区。
(4)活区显示。格式:p<回车>
逐页地(每页 20 行)显示活区内容,每显示一页之后请用户决定是否继续显示以后各
页(如果存在)。印出的每一行要前置以行号和一个空格符,行号固定占 4 位,增量为 1。
各条命令中的行号均须在活区中各行行号范围之内,只有插入命令的行号可以等于活区
第一行行号减 1,表示插入当前屏幕中第一行之前,否则命令参数非法。
13 [选作内容] (1) 对于命令格式非法等一切错误作严格检查和适当处理。 (2) 加入更复杂的编辑操作,如对某行进行串替换;在活区内进行模式匹配
二、要解决的问题
(1) 行插入。
(2)行删除。
(3)活区切换。
(4)活区显示。
附加:
(5)在活区内进行多或单模式匹配
三、算法基本思想描述:
对于题目的要求,在进行活区切换及显示,行插入,行删除,模式匹配都要求涉及链表,所以对链表进行的基本操作在课设中有所体现,而在附加功能中,使用了AC自动机,进行匹配,来提高时间效率。
AC自动机,其实类似于字典树+KMP算法,通过构建匹配失败后的fail指针,来构建AC自动机的模式匹配树,而fail的构建涉及bfs算法,而fail的构建算法,首先先将连接于root的点的所有子节点连向root的点,再将所有非NULL的点压入队列,弹出进行操作,考虑节点失配的情况,让失配的节点p->next[i]->fail=p->fail->next[i];这个过程后就可以建立一颗带fail节点的字典树。
而在自动机的匹配过程中就是按照生成的fail树对应匹配。即匹配失败就移动到p->next[i]->fail.
顺带补充下字典树的建立,
本课设的字典树是采用指针版,即一个节点下有对应的30的子指针,代表a-z,然后如果为空即代表没有这个字母。如果不为空,这代表有这个字母,假设abc,fde建立的字典树如图:


四、设计
1. 数据结构的设计
(1)储存结构:
1.
const int MAXN = 81;
const int MAXNS = 1024;
char file_name[MAXNS]; ///储存用户输入的地址
char file_ends_name[MAXNS]; ///储存文本输出的地址
char AC_TIRE_ARR[325 * 25];///代表AC自动机要匹配的数组
2.读出和读入文件的数据结构:
typedef struct NODE
{
char words[MAXN];///代表每个节点中储存的数据
struct NODE *next;///指向下一个节点
int num; ///代表行数(供输出的时候使用)
bool flag; ///flag代表行结束,行没结束时,flag==false,结束时///将其标记为true
} node;
3.AC自动机中的字典树的数据结构
typedef struct TIRE
{
struct TIRE *next[30];///代表指向字典树子节点
bool flag;///代表匹配串是否结束了
struct TIRE *fail;///指向失配后的位置
} tire;


2.算法的设计
2.1函数的思路详解
(1)向系统申请node类型的空间,并返回给node型指针
node *creat()
(2)判断读取的数据是否为文件尾的数据
bool PD1(char word[]) ///判断行是否结束
其主要思路通过对数组word的strlen(word)-1来进行判断,因为txt文档中的数据读取一行的话,行末会带’\n’,所以’\n’可以代表一行的结束
(3)从文件中读取到链表中来构建数据。
int get_hang(char fileopenname[MAXNS], node *head, int move, int &fflag)
使用fgets函数从文件中读取一行中的81个字符到储存数据的链表中,然后在读取到一行结束的时候把node结构体中的flag=true,来标记结束。
(4)输出从文件中读取到链表的内容
void PRINTNODE(node *head) ///输出链表
通过head来读取数据,如果遇到flag==true的就证明,该行到达了结束,输出换行,接着输出该节点的序号,然后循环。
(5),清空函数
void clearl(node *p)///释放链表,防止内存泄露
void clear()///清屏函数
(6)///菜单生成表
void view()
(7)针对于添加后超出活区限制,提交到文件中
void only_insert(char strs[305], node *&head)///把第一行输出到文本中
因为题意中表明了,会出现添加超过了活区的情况,那么我就将活区链表的第一个节点提交到文件中,并且将第一个节点经行移动。然后重新建立序号。
(8)把修改后的活区读入文件中
void INPUT_file(char file_sname[MAXNS], node *head)
通过申请一个中转数组来储存第一行的数据,通过对链表的读取来储存数据,然后通过fput读入文件。
(9),代表删除一个行区间
其原理为

void del_file_one(int ans1, int ans2, node *&head) ///代表删除一个区间
采用两个指针来实现,一个指向要删除的行的前一个的节点,一个指向后一个节点,采用将前一个指针指向后一个指针来实现区间删除。
关于删除第一个节点,直接将头指针移动到下一个行节点。就可以了。
多出来的节点可以通过删除函数进行删除。

(10),删除单行
void del_file_two(int ans1, node *&head)
原理也是采用两个两个节点来跑,一个指向要删除的行的前一个的节点,一个指向后一个节点,采用将前一个指针指向后一个指针来实现单行删除。
原理图跟上述一样
(11),创建AC自动机的字典树部分的节点
tire *creat_tire()
申请一个节点,并且将其相连的子节点==NULL
然后把标记变成0;标记的意思是是否走到这个子匹配串的末尾。
(12),在字典树中插入匹配子串
一个节点下有对应的30的子指针,代表a-z,然后如果为空即代表没有这个字母。如果不为空,这代表有这个字母,假设abc,fde建立的字典树如图:


void insert_tire(char words[], tire *root)
思路就是对子串数组进行遍历,如果第一个节点下的对应节点为NULL的话就建立这个节点,而建立的方式有个核心,就是next【ans】,ans=words【i】-’a’;
来获取,应用了ascii码的运算
(13)生成fail指向
/**
通过构建匹配失败后的fail指针,来构建AC自动机的模式匹配树,而fail的构建涉及bfs算法,而fail的构建算法,首先先将连接于root的点的所有子节点连向root的点,再将所有非NULL的点压入队列,弹出进行操作,考虑节点失配的情况,让失配的节点p->next[i]->fail=p->fail->next[i];这个过程后就可以建立一颗带fail节点的字典树。涉及bfs,即广度优先搜索!
而在自动机的匹配过程中就是按照生成的fail树对应匹配。即匹配失败就移动到p->next[i]->fail.

**/
void build_ACtire(tire *root)
(14)查找匹配的位置
如图:

bool ACTIRE_search(char str[], tire *root)

将查找串与匹配串所建立的fail树进行匹配,如果匹配失败就访问匹配失败的fail指针再次经行匹配。匹配成功就返回匹配的的字段的位置。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <queue>
#include <vector>
using namespace std;
const int MAXN = 81;
const int MAXNS = 1024;
char file_name[MAXNS];      ///用户输入的地址
char file_ends_name[MAXNS]; ///文本输出的地址
char AC_TIRE_ARR[325 * 25];
typedef struct NODE
{
    char words[MAXN];
    struct NODE *next;
    int num;   ///代表行数
    bool flag; ///flag代表行结束
} node;
typedef struct TIRE
{
    struct TIRE *next[30];
    bool flag;
    struct TIRE *fail;
} tire;
node *head;
node *creat()
{
    node *p;
    p = new node;
    memset(p->words, 0, sizeof(p->words));
    p->num = 1;
    p->flag = false;
    p->next = NULL;
    return p;
}
bool PD1(char word[]) ///判断行是否结束
{
    int len = strlen(word);
    if (word[len - 1] == '\n')
    {
        return true;
    }
    else
        return false;
}
int get_hang(char fileopenname[MAXNS], node *head, int move, int &fflag) ///fflag代表是否读到文件尾
{
    FILE *fp;
    int re; ///代表字节数
    int biaoji = 0;
    re = 0;
    fp = fopen(fileopenname, "r");
    fseek(fp, move, 0);
    int number = 1; ///number代表行数
    while (fgets(head->words, 81, fp) != NULL)
    {
        re += (strlen(head->words) + 1);
        //printf("%d\n",re);
        if (PD1(head->words))
        {
            number++;
            if (number == 21)
            {
                fflag = 1;
                break;
            }
            head->flag = true;
            node *p;
            p = creat();
            p->num = number;
            head->next = p;
            head = head->next;
        }
        else
        {
            node *p;
            p = creat();
            p->num = number;
            head->next = p;
            head = head->next;
        }
    }
    fclose(fp);
    return re;
}
void PRINTNODE(node *head) ///输出链表
{
    if (head == NULL)
    {
        printf("error,no thing\n");
        return;
    }
    printf("%4d ", head->num);
    while (head)
    {
        printf("%s", head->words);
        if (head->flag == true)
        {
            //printf("...\n");
            int lens = strlen(head->words);
            if (head->words[lens - 1] != '\n')
                printf("\n"); ///这个是针对于添加之后的。
            if (head->next != NULL)
                printf("%4d ", head->next->num);
        }
        head = head->next;
    }
    //puts("");
}
void clearl(node *p)
{
    if (p != NULL)
    {
        clearl(p->next);
        free(p);
    }
}
void clear()
{
    system("cls");
}
void view()
{
    printf("\n");
    printf("活区切换。格式:n<回车>\n");
    printf("活区显示。格式:p<回车> \n");
    printf("行插入。格式:i<行号><回车><文本><回车> \n");
    printf("行删除。格式:d<行号 1>[ <行号 2>]<回车> \n");
    printf("活区多或单模式匹配。 格式:m<模式串 1>[ <模式串 2> ......]<回车>\n");
}
void only_insert(char strs[305], node *&head)
{
    node *hhead;
    hhead = head;
    int j = 0;
    char wordss[325];
    int ans;
    while (hhead->flag == false)
    {
        ans = strlen(hhead->words);
        for (int i = 0; i < ans; i++)
        {
            wordss[j] = hhead->words[i];
            j++;
            //printf("...........\n");
        }
    }
    ans = strlen(hhead->words);
    for (int i = 0; i < ans; i++)
    {
        //printf("%c",hhead->words[i]);
        wordss[j] = hhead->words[i];
        j++;
    }
    if (wordss[j - 1] != '\n')
        wordss[j] = '\n';
    FILE *fp = fopen(strs, "a+");
    fputs(wordss, fp);
    fclose(fp);
    hhead = hhead->next;
    head = hhead;
}
void add_hang(int n, node *&head)
{
    int j = 0;
    node *p;
    node *begins;
    node *headss = creat();
    node *heads = creat();
    begins = creat();
    p = creat();
    heads = head;
    headss = head;
    begins = p;
    p->num = n + 1;
    char str[355];
    printf("please the words \n");
    cin >> str;
    getchar();
    int len = strlen(str);
    for (int i = 0; i < len; i++)
    {
        p->words[j++] = str[i];
        if (j == 81)
        {
            j = 0;
            node *q;
            q = creat();
            q->num = n + 1;
            p->next = q;
            p = p->next;
        }
    }
    //p->words[j]='\n';
    p->flag = true;
    if (n == 0)
    {
        p->next = head;
        head = p;
        headss = head;
        //printf("%s\n",head->words);
        int numbers = 1;
        while (headss)
        {
            headss->num = numbers;
            if (headss->flag == true && headss->next != NULL)
            {
                numbers++;
            }
            headss = headss->next;
        }
        //PRINTNODE(head);
        if (numbers > 20)
        {
            only_insert(file_ends_name, head);
        }
        node *hhead;
        hhead = creat();
        hhead = head;
        numbers = 1;
        while (hhead)
        {
            hhead->num = numbers;
            if (hhead->flag == true)
            {
                numbers++;
            }
            hhead = hhead->next;
        }
    }
    else
    {
        while (headss->next->num != begins->num)
        {
            //printf("%d\n",headss->next->num);
            headss = headss->next;
            if (headss->next == NULL)
            {
                break;
            }
        }
        headss->flag = true;
        p->next = headss->next;
        headss->next = begins;
        int numbers = 1;
        while (heads)
        {
            heads->num = numbers;
            if (heads->flag == true && heads->next != NULL)
            {
                numbers++;
            }
            heads = heads->next;
        }
        //PRINTNODE(head);
        if (numbers > 20)
        {
            only_insert(file_ends_name, head);
        }
        node *headsss;
        headsss = creat();
        headsss = head;
        numbers = 1;
        while (headsss)
        {
            headsss->num = numbers;
            if (headsss->flag == true)
            {
                numbers++;
            }
            headsss = headsss->next;
        }
    }
}
void INPUT_file(char file_sname[MAXNS], node *head)
{
    char buf[MAXN * 10];
    memset(buf, 0, sizeof(buf));
    FILE *fps = fopen(file_sname, "a+");
    int j = 0;
    while (head)
    {
        int len = strlen(head->words);
        for (int i = 0; i < len; i++)
        {
            buf[j] = head->words[i];
            j++;
        }
        if (head->flag == true && head->next == NULL)
        {
            //printf("%s\n",buf);
            fputs(buf, fps);
            j = 0;
            memset(buf, 0, sizeof(buf));
        }
        if (head->flag == false && head->next == NULL)
        {
            fputs(buf, fps);
            j = 0;
            memset(buf, 0, sizeof(buf));
        }
        if (head->flag == true && head->next != NULL)
        {
            int lens = strlen(head->words);
            if (head->words[lens - 1] != '\n')
                buf[j] = '\n';
            fputs(buf, fps);
            j = 0;
            memset(buf, 0, sizeof(buf));
        }
        head = head->next;
    }
    fclose(fps);
}
void Node_clear(node *s, node *h)
{
    while (s != h)
    {
        //printf("...........\n");
        Node_clear(s->next, h);
        delete s;
    }
}
void del_file_one(int ans1, int ans2, node *&head) ///代表删除一个区间
{
    node *head1; ///代表指向前一个的指针
    head1 = creat();
    node *head2; ///代表指向后一个的指针
    head2 = creat();
    node *head3; ///释放内存空间
    head3 = creat();
    node *head4;
    head4 = creat();
    head1 = head;
    head2 = head;
    ///ans1 ans2 0 10 代表0到10都被删除
    if (ans1 != 1)
    {
        while (head1->next->num != ans1)
        {
            head1 = head1->next;
        }
        while (head2->next->num != ans2 + 1)
        {
            head2 = head2->next;
            if (head2->next == NULL)
            {
                break;
            }
        }
        head3 = head1->next;
        head4 = head2;
        head1->next = head2->next;
        //Node_clear(head3,head2);
        /**
        以下是一个重新构造输出数据的函数
        **/
        node *heads;
        heads = creat();
        heads = head;
        int numbers = 1;
        while (heads)
        {
            heads->num = numbers;
            if (heads->flag == true)
            {
                numbers++;
            }
            heads = heads->next;
        }
    }
    else if (ans1 == 1)
    {
        while (head2->next->num != ans2 + 1)
        {
            head2 = head2->next;
            if (head2->next == NULL)
            {
                break;
            }
        }
        //printf("%s\n",head2->words);
        head3 = head;
        head4 = head2;
        head2 = head2->next;
        head = head2;
        //Node_clear(head3,head4);
        node *headss;
        headss = creat();
        headss = head;
        int numbers = 1;
        while (headss)
        {
            headss->num = numbers;
            if (headss->flag == true)
            {
                numbers++;
            }
            headss = headss->next;
        }
    }
}
void del_file_two(int ans1, node *&head)
{
    if (ans1 == 1)
    {
        node *heads;
        heads = creat();
        heads = head;
        while (heads->next->num == 1)
        {
            heads = heads->next;
            if (heads->next == NULL)
            {
                break;
            }
        }
        heads = heads->next;
        head = heads;
        node *head1;
        head1 = creat();
        head1 = head;
        int numbers = 1;
        while (head1)
        {
            head1->num = numbers;
            if (head1->flag == true)
            {
                numbers++;
            }
            head1 = head1->next;
        }
    }
    else
    {
        int ans2 = ans1 + 1;
        node *head1;
        head1 = creat();
        head1 = head;
        node *head2;
        head2 = creat();
        head2 = head;
        while (head1->next->num != ans1)
        {
            head1 = head1->next;
            if (head1->next == NULL)
                break;
        }
        while (head2->next->num != ans2)
        {
            head2 = head2->next;
            if (head2->next == NULL)
            {
                break;
            }
        }
        head2 = head2->next;
        head1->next = head2;
        int nums = 1;
        node *head3;
        head3 = creat();
        head3 = head;
        while (head3)
        {
            head3->num = nums;
            if (head3->flag == true)
                nums++;
            head3 = head3->next;
        }
    }
}
tire *creat_tire()
{
    tire *p;
    p = new tire;
    p->flag = false;
    for (int i = 0; i < 30; i++)
    {
        p->next[i] = NULL;
    }
    p->fail = NULL;
    return p;
}
//tire *root = creat_tire();
void insert_tire(char words[], tire *root)
{
    int len;
    len = strlen(words);
    tire *p;
    p = root;
    for (int i = 0; i < len; i++)
    {
        int ans;
        ans = words[i] - 'a';
        //printf("%d\n",ans);
        if (p->next[ans] == NULL)
        {
            tire *q;
            q = creat_tire();
            p->next[ans] = q;
        }
        p = p->next[ans];
    }
    p->flag = true; ///代表结束
}
void build_ACtire(tire *root)
{
    tire *p = root;
    tire *q;
    queue<tire *> que;
    for (int i = 0; i < 30; i++)
    {
        if (p->next[i] != NULL)
        {
            p->next[i]->fail = root;
            que.push(p->next[i]);
        }
        else
            p->next[i] = root;
    }
    while (!que.empty())
    {
        tire *to;
        to = que.front();
        que.pop();
        for (int i = 0; i < 30; i++)
        {
            ///因为第一个模式串如果匹配失败,有可能是另一个匹配串
            ///所以应该找到另一个
            ///失配的话,就是回到root点再寻找
            if (to->next[i] != NULL)
            {
                to->next[i]->fail = to->fail->next[i];
                que.push(to->next[i]);
            }
            else
                to->next[i] = to->fail->next[i];
        }
    }
}
bool ACTIRE_search(char str[], tire *root)
{
    vector<int> vec;
    int len = strlen(str);
    //printf("%d\n",len);
    tire *ans;
    ans = creat_tire();
    ans = root;
    for (int i = 0; i < len; i++)
    {
        int num = str[i] - 'a';
        if (num < 0)
            continue;
        //printf("%d...\n",num);
        if (ans->next[num] != NULL)
        {
            ans = ans->next[num];
            //printf("%d....\n",ans->flag);
            if (ans->flag == true)
            {
                //if(ans==NULL)
                //printf("............................................\n");
                vec.push_back(i);
            }
        }
        else
        {
            if (ans == root)
                i++;
            else
            {
                ans = ans->fail;
                if (ans->flag == true)
                {
                    vec.push_back(i);
                }
            }
        }
    }
    if (vec.size() != 0)
    {
        for (int i = 0; i < vec.size(); i++)
        {
            printf("%d ", vec[i]);
        }
        puts("");
        return true;
    }
    return false;
}
int main()
{
    int file_move = 0;
    node *p;
    int end_flag = 0;
    printf("please cin the in file_name\n");
    cin >> file_name;
    getchar();
    printf("please cin the out file_name\n");
    cin >> file_ends_name;
    getchar();
    while (1)
    {
        view();
        node *head;
        char s[100];
        char strs[105];
        int nums;
        gets(s);
        if (s[0] == 'n')
        {
            if (file_move == 0)
            {
                head = creat();
                nums = get_hang(file_name, head, file_move, end_flag);
                if (nums == 0)
                {
                    printf("error\n");
                    continue;
                }
                file_move += nums;
                PRINTNODE(head);
            }
            else
            {
                INPUT_file(file_ends_name, head);
                head = creat();
                nums = get_hang(file_name, head, file_move, end_flag);
                if (nums == 0)
                {
                    printf("the file open is error\n");
                    printf("because the file is end\n");
                    continue;
                }
                file_move += nums;
                PRINTNODE(head);
            }
        }
        if (s[0] == 'p')
        {
            PRINTNODE(head);
        }
        if (s[0] == 'i')
        {
            int ans = 0;
            int len;
            len = strlen(s);
            for (int i = 1; i < len; i++)
            {
                if (s[i] >= '0' && s[i] <= '9')
                {
                    ans = ans * 10 + (s[i] - '0');
                }
                else
                    break;
            }
            add_hang(ans, head);
        }
        if (s[0] == 'd')
        {
            int ans1, ans2;
            ans1 = 0;
            ans2 = 0;
            int i;
            int len = strlen(s);
            for (i = 1; i < len; i++)
            {
                if (s[i] >= '0' && s[i] <= '9')
                {
                    ans1 = ans1 * 10 + (s[i] - '0');
                }
                else
                    break;
            }
            if (i == len)
            {
                del_file_two(ans1, head);
            }
            else
            {
                for (i = i + 1; i < len; i++)
                {
                    if (s[i] >= '0' && s[i] <= '9')
                    {
                        ans2 = ans2 * 10 + (s[i] - '0');
                    }
                    else
                        break;
                }
                del_file_one(ans1, ans2, head);
            }
        }
        if (s[0] == 'm')
        {
            tire *root = creat_tire();
            root = new tire;
            root->flag = false;
            for (int i = 0; i < 30; i++)
                root->next[i] = NULL;
            root->fail = NULL;
            char hzb[MAXN * 2];
            memset(hzb, 0, sizeof(hzb));
            int hzblen = strlen(s);
            int hzbj = 0;
            for (int i = 1; i < hzblen; i++)
            {
                if (s[i] == ' ')
                {
                    hzb[hzbj] = '\0';
                    //printf("%s\n", hzb);
                    insert_tire(hzb, root);
                    hzbj = 0;
                    continue;
                }
                hzb[hzbj++] = s[i];
            }
            hzb[hzbj] = '\0';
            //printf("%s\n", hzb);
            insert_tire(hzb, root);
            build_ACtire(root);
            node *hzb_head;
            hzb_head = creat();
            hzb_head = head;
            memset(AC_TIRE_ARR, 0, sizeof(AC_TIRE_ARR));
            int hzbz = 0;
            while (hzb_head)
            {
                int hhzb = strlen(hzb_head->words);
                for (int i = 0; i < hhzb; i++)
                    if (hzb_head->words[i] != '\n')
                        AC_TIRE_ARR[hzbz++] = hzb_head->words[i];
                hzb_head = hzb_head->next;
            }
            AC_TIRE_ARR[hzbz] = '\0';
            bool hflag = ACTIRE_search(AC_TIRE_ARR, root);
            if (hflag == false)
                printf("sorry!this is nothing\n");
        }
    }
    return 0;
}

 

posted @ 2018-06-26 22:32  moxin0509  阅读(3173)  评论(2编辑  收藏  举报