山东大学程序设计思维与实践 五月模拟-记事本

5月模拟-记事本
山东大学计算机科学与技术学院程序设计思维与实践作业
山大程序设计思维与实践
sdu程序设计思维与实践
山东大学程序设计思维与实践

相关资料:GitHub

记事本

注:本题有较多的部分分,请参看数据规模部分。

题目描述
记事本是 Windows 平台下一款经典的文本编辑器,其存储文件的扩展名为 .txt,文件属性没有任何格式标签或者风格,所以相当适合在 DOS 环境中编辑。

在本题中,可能会用到的按键如下图所示:

key.png

光标移动
光标表示当前要进行输入等操作的位置,在本题中,我们假设所有字符都是等宽的。

光标的位置可以用行列坐标来描述,光标所在的行和列均从 1 开始,例如:

在这里插入图片描述

以下操作可以进行光标的移动,使用 MOVE 输入相关的操作,其中 表示指令,可以使用以下字符串代替:

Home:把光标移动到当前行的开头。
End:把光标移动到当前行的末尾。
Up:光标移动到上一行的相同列。
若当前为第一行,则不进行任何操作。
若上一行的列数小于当前光标的列数,则将光标移动到上一行的末尾。
Down:光标移动到下一行的相同列。
若当前为最后一行,则不进行任何操作。
若下一行的列数小于当前光标的列数,则将光标移动到下一行的末尾。
Left:光标左移一位。
若当前光标位于记事本开始,则不进行任何操作。
若当前光标处于某一行的开头,则将光标移动到上一行的末尾。
Right:光标右移一位。
若当前光标位于记事本末尾,则不进行任何操作。
若当前光标处于某一行的末尾,则将光标移动到下一行的开头。
输入
以下操作可以在光标后进行输入,使用 INSERT 输入相关的操作,其中 表示指令,可以使用以下字符串代替:

Char :输入一个字符,其中 是输入的字符。

可能是一下字符中的任意一个:
注:下列字符中不包含空格与换行符。

`1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:"zxcvbnm,./ZXCVBNM<>?
例如:INSERT Char a 表示在当前光标后插入 a 字符。
Enter:输入换行符,并进行换行。

Space:输入空格。

Paste:在当前光标后,插入粘贴板中的内容,若粘贴板中无内容,则忽略当前操作。

删除
以下操作可以删除记事本中的内容,使用 REMOVE 输入相关的操作,其中 表示指令,可以使用以下字符串代替:

Del:删除当前光标位置之后的一个字符。
若该字符为换行符,则当前行与下一行合并为一行。
若当前光标在文件末尾,则忽略当前操作。
Backspace:删除当前光标位置之前的一个字符。
若该字符为换行符,则当前行与上一行合并为一行。
若当前光标在文件开头,则忽略当前操作。
粘滞功能(分数占比 24 分)
输入 SHIFT 指令,可以启动或关闭粘滞功能。

开始时粘滞功能默认为关闭状态,之后每次点击:

若当前为启动状态,则关闭;
若当前为关闭状态,则启动。
粘滞功能启动时,记录当前的光标位置为 记录点。

粘滞功能关闭时,若此时的光标位置与 记录点 的位置不同,则进入选中状态。

粘滞功能启动后,直到功能关闭前,不会对记事本进行除光标移动外的任何操作。

当进入选中状态后,通过记录点与当前光标,可以唯一的确定一段内容,现令记录点与光标之间的所有字符(包括换行符)为 选中字段。

例如,记录点位于第 1 行第 2 列,光标位于第 2 行第 4 列时,选中字段如下图所示:

image.png

当前 处于选中状态 时,对于不同的情况,需要按照序号依次执行以下操作:

若进行光标移动:

退出选中状态;
尝试进行光标的移动(无论光标最终是否移动,都会退出选中状态)。
若进行输入:

将选中内容替换为输入内容;
退出选中状态。
若进行删除:

删除当前选中内容;
退出选中状态。
若再次启动粘滞功能:退出选中状态,但保留上一次选中字段的 记录点 作为当前记录点。

若进行查找,字数统计,复制,打印操作,则在操作后仍然保持选中状态。

查找
输入 FIND 指令,进行字符串查找,其中 为输入的要查找的字符串,该字符串中不包含空格与换行符。

执行该指令时,要根据当前是否处于选中状态做不同的处理:

若当前处于选中状态:查找输入字符串在选中字段中的出现次数并输出。
否则:查找输入字符串在当前记事本中的出现次数并输出。
例如:当前没有选中的内容,且记事本中的内容为 ababa,若执行 FIND aba,则应当输出 2,分别在第 1 列与第 3 列出现过。

字数统计
输入 COUNT 指令,进行字数统计。

执行该指令时,要根据当前是否处于选中状态做不同的处理:

若当前处于选中状态:输出当前选中字段中的可见字符(不包括空格与换行符)的数量。
否则:输出当前文档中可见字符(不包括空格与换行符)的数量。
复制
输入 COPY 指令,进行复制操作。

执行该指令时,要根据当前是否处于选中状态做不同的处理:

若当前处于选中状态:复制选中字段到粘贴板;
否则,
若当前行不为空:复制当前行的内容(不包括换行符)到粘贴板;
否则:忽略当前操作。
打印
输入 PRINT 指令,输出当前的记事本中的全部内容,并在之后输出一个换行符。

输入格式
输入包含 n+1 行。
第一行包含一个整数 n,表示接下来指令的数量。
接下来 n 行,每行一条指令,格式形如题目描述中的叙述。

输出格式
对于需要输出的指令,进行相应的输出。
若为 FIND 与 COUNT 操作,输出一行表示相应的数字。
若为 PRINT 操作,则输出若干行,表示记事本的当前内容,并在之后输出一个换行。

请注意:所有的输出不要有多余的空格。

测试样例
样例输入
20
INSERT Char #
INSERT Enter
INSERT Char C
INSERT Enter
INSERT Space
INSERT Char _
INSERT Char _
PRINT
INSERT Char >
INSERT Enter
INSERT Char h
INSERT Char h
INSERT Char h
INSERT Enter
PRINT
COUNT
FIND __
REMOVE Del
REMOVE Backspace
PRINT

样例输出

C
__

C
__>
hhh

8
1

C
__>
hhh

C
__

C
__>
hhh

8
1

C
__>
hhh

#include <bits/stdc++.h>
using namespace std;
vector<string> text;
deque<string> pst;
pair<int, int> cursor, mark, st, ed;
bool chs;

void delSE() {
    int delst = INT_MAX, deled = INT_MIN;
    for (int i = st.first; i <= ed.first; i++) {
        if (i < ed.first) {
            if (i == st.first) {
                text[i - 1].erase(st.second - 1);
            } else {
                delst = min(delst, i);
                deled = max(deled, i);
            }
        } else {
            if (i == st.first) {
                text[i - 1].erase(st.second - 1, ed.second - st.second);
            } else {
                text[i - 1].erase(0, ed.second - 1);
                text[st.first - 1].append(text[i - 1]);
                delst = min(delst, i);
                deled = max(deled, i);
            }
        }
    }
    if (delst != INT_MAX && deled != INT_MIN) {
        text.erase(text.begin() + delst - 1, text.begin() + deled);
    }
    cursor = st;
}

vector<int> prefix_function(string s) { //字符串前缀函数
    int n = s.length();
    vector<int> vec(n);
    for (int i = 1; i < n; i++) {
        int j = vec[i - 1];
        while (j > 0 && s[i] != s[j])
            j = vec[j - 1];
        if (s[i] == s[j])
            j++;
        vec[i] = j;
    }
    return vec;
}

void move(string command) {
    if (command == "Home") {
        cursor.second = 1;
    }
    if (command == "End") {
        if (chs)
            cursor = ed;
        cursor.second = text[cursor.first - 1].size() + 1;
    }
    if (command == "Up") {
        if (cursor.first > 1) { //-2是因为下标访问需要-1
            cursor.second = text[cursor.first - 2].size() + 1 < cursor.second ? text[cursor.first - 2].size() + 1
                                                                              : cursor.second;
            cursor.first--;
        }
    }
    if (command == "Down") {
        if (cursor.first < text.size()) { //没有+1因为下标访问需要-1
            cursor.second =
                    text[cursor.first].size() + 1 < cursor.second ? text[cursor.first].size() + 1 : cursor.second;
            cursor.first++;
        }
    }
    if (command == "Left") {
        if (cursor.first != 1 || cursor.second != 1) {
            if (cursor.second == 1) {
                cursor.first--;
                cursor.second = text[cursor.first - 1].size() + 1;
            } else {
                cursor.second--;
            }
        }
    }
    if (command == "Right") {
        if (cursor.first != text.size() ||
            cursor.second != text.back().size() + 1) {
            if (cursor.second == text[cursor.first - 1].size() + 1) {
                cursor.first++;
                cursor.second = 1;
            } else {
                cursor.second++;
            }
        }
    }
}

void insert(const string &command) {
    if (chs) {
        delSE();
        chs = false;
    }
    if (command == "Char") {
        string tmp;
        cin >> tmp;
        text[cursor.first - 1].insert(cursor.second - 1, tmp);
        cursor.second++;
    }
    if (command == "Enter") {
        string tmp =
                text[cursor.first - 1].substr(cursor.second - 1); //获取子串
        text[cursor.first - 1].erase(cursor.second - 1);      //删除子串
        text.insert(text.begin() + cursor.first, tmp);
        cursor.first++;
        cursor.second = 1;
    }
    if (command == "Space") {
        text[cursor.first - 1].insert(cursor.second - 1, " ");
        cursor.second++;
    }
    if (command == "Paste") {
        if (!pst.empty()) {
            auto tpst = pst;
            pair<int, int> ptr = cursor;
            string tmp = text[cursor.first - 1].substr(cursor.second - 1);
            if (!tmp.empty()) {
                text[cursor.first - 1].erase(text[cursor.first - 1].begin() +
                                             cursor.second - 1, text[cursor.first - 1].end());
            }
            text[cursor.first - 1].append(pst.front());
            pst.pop_front();
            while (!pst.empty()) {
                text.insert(text.begin() + cursor.first, pst.back());
                pst.pop_back();
                ptr.first++;
            }
            ptr.second = text[ptr.first - 1].size() + 1;
            text[ptr.first - 1].append(tmp);
            cursor = ptr;
            pst = tpst;
        }
    }
}

void remove(const string &command) {
    if (chs) {
        delSE();
        chs = false;
        return;
    }
    if (command == "Del") {
        if (cursor.first != text.size() || cursor.second != text.back().size() + 1) { //不在文件末尾
            if (cursor.second == text[cursor.first - 1].size() + 1) { //行末
                text[cursor.first - 1].append(text[cursor.first]);
                text.erase(text.begin() + cursor.first);
            } else {
                text[cursor.first - 1].erase(text[cursor.first - 1].begin() +
                                             cursor.second - 1);
            }
        }
    }
    if (command == "Backspace") {
        if (cursor.first != 1 || cursor.second != 1) {
            if (cursor.second == 1) {
                auto tmp = text[cursor.first - 2].size() + 1;
                text[cursor.first - 2].append(text[cursor.first - 1]);
                text.erase(text.begin() + cursor.first - 1);
                cursor.second = tmp;
                cursor.first--;
            } else {
                text[cursor.first - 1].erase(text[cursor.first - 1].begin() +
                                             cursor.second - 2);
                cursor.second--;
            }
        }
    }
}

int Find(string &word) {
    if (chs) {
        string cmp;
        int result = 0;
        for (int i = st.first; i <= ed.first; i++) {
            if (i < ed.first) {
                if (i == st.first) {
                    cmp = text[i - 1].substr(st.second - 1);
                } else {
                    cmp = text[i - 1];
                }
            } else {
                if (i == st.first) {
                    cmp = text[i - 1].substr(st.second - 1,
                                             ed.second - st.second);
                } else {
                    cmp = text[i - 1].substr(0, ed.second - 1);
                }
            }

            string tp = word + "\n";
            for (char i : cmp) {
                tp += i;
                auto vec = prefix_function(tp);
                if (vec[tp.size() - 1] == word.size())
                    result++;
            }
        }
        return result;
    }

    int result = 0;
    for (auto & i : text) {
        string tp = word + "\n";
        for (int j = 0; j < i.size(); j++) {
            tp += i[j];
            auto vec = prefix_function(tp);
            if (vec[tp.size() - 1] == word.size())
                result++;
        }
    }
    return result;
}

int countNum(string s) {
    int n = 0;
    for (auto j: s) {
        if (j != ' ')
            n++;
    }
    return n;
}

int count() {
    if (chs) {
        int n = 0;
        for (int i = st.first; i <= ed.first; i++) {
            if (i < ed.first) {
                if (i == st.first) {
                    n += countNum(text[i - 1].substr(st.second - 1));
                } else {
                    n += countNum(text[i - 1]);
                }
            } else {
                if (i == st.first) {
                    n += countNum(text[i - 1].substr(st.second - 1,
                                                     ed.second - st.second));
                } else {
                    n += countNum(text[i - 1].substr(0, ed.second - 1));
                }
            }
        }
        return n;
    }

    int n = 0;
    for (const auto& i: text) {
        n += countNum(i);
    }
    return n;
}

void copy() {
    if (chs) {
        pst.clear();
        for (int i = st.first; i <= ed.first; i++) {
            if (i < ed.first) {
                if (i == st.first) {
                    pst.push_back(text[i - 1].substr(st.second - 1));
                } else {
                    pst.push_back(text[i - 1]);
                }
            } else {
                if (i == st.first) {
                    pst.push_back(text[i - 1].substr(st.second - 1,
                                                     ed.second - st.second));
                } else {
                    pst.push_back(text[i - 1].substr(0, ed.second - 1));
                }
            }
        }
        return;
    }

    if (!text[cursor.first - 1].empty()) {
        pst.clear();
        pst.push_back(text[cursor.first - 1]);
    }
}

void moveInSht(int &i) {
    string op;
    if (!chs) {
        mark = cursor;
    }else{
        chs = false;
    }
    while (cin >> op && op != "SHIFT") {
        string command;
        cin >> command;
        move(command);
        i++;
    }
    i++;
    if (cursor != mark) {
        st = cursor < mark ? cursor : mark;
        ed = cursor < mark ? mark : cursor;
        chs = true;
    }
}

void print() {
    for (const auto& i: text)
        cout << i << endl;
}

int main() {
    int n;
    cin >> n;
    cursor = {1, 1};
    chs = false;
    text.push_back("");

    for (int i = 1; i <= n; i++) {
        string op;
        cin >> op;
        if (op == "MOVE") {
            chs = false;
            string command;
            cin >> command;
            move(command);
            continue;
        }
        if (op == "INSERT") {
            string command;
            cin >> command;
            insert(command);
            continue;
        }
        if (op == "REMOVE") {
            string command;
            cin >> command;
            remove(command);
            continue;
        }
        if (op == "FIND") {
            string word;
            cin >> word;
            cout << Find(word) << endl;
            continue;
        }
        if (op == "COUNT") {
            cout << count() << endl;
            continue;
        }
        if (op == "COPY") {
            copy();
            continue;
        }
        if (op == "PRINT") {
            print();
            continue;
        }
        if (op == "SHIFT") {
            moveInSht(i);
            continue;
        }
    }
    return 0;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值