设计一个文本行编辑程序
- 对文本文件按行进行编辑:先从输入文件中读取数据,然后根据行编辑命令处理,将结果写到输出文件中。
- 行编辑命令包括:
序号 | 行编辑命令格式 | 功能 |
1 | *L m,n | 显示从第m至n行的文本 |
2 | *I m …… ^Z | 插入文本(……)在第m行后 |
3 | *D m,n | 删除从第m至n行的文本 |
4 | *R m,n …… ^Z | 用文本(……)替换第m至n行的文本 |
5 | *X | 保存并退出编辑程序 |
6 | *Q | 放弃并退出程序 |
文本编辑在日常生活中尤为重要,无论是写论文,做表格等等都离不开文本编辑,而比较热门的编辑器,如:微软Word,Excel等都有着相当完整且多样的功能,而很多功能一般只需要点击图标或者设置就能完成,这也离不开软件背后的相关命令的设置,而规范化,模块化的文本编辑指令又有着方便识别和管理的优点,因此面向文本编辑的程序设计的用途是广泛且重要的。
- 命令中含有较多插入和删除操作,采用链表存储更方便。
- 规范化输入,所有的执行都要取决于其命令类型,因此设置一个string型数组存储所有命令类型,每当输入一个命令类型时遍历数组,然后根据相等时所在位置进行Switch case语句,亦或是判断合法。
- 详细化输入,针对不同类型给予不同的输入方式,插入文本应该以换行符为标准进行换行读取。
- 保存编辑即为把链表所有内容以turnc形式写入,放弃编辑则直接return 0;
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
typedef struct N {
string s;
struct N* next;
}Node;
int len = 0; /*链表长度*/
string file; /*访问文件路径*/
int main() {
Node* begin = new Node(); /*文本链表*/
Node* end = begin;
ifstream ifs;
while (true) {
file = "testpage.dat";
ifs.open(file, ios::in);
if (file == "null")return 0;
else {
string buf; //读入原有内容到链表
while (getline(ifs, buf))
{
Node* n = new Node();
n->next = NULL;
n->s = buf;
end->next = n;
end = n;
len++;
}
ifs.close();
break;
}
}
string command[] = { "*L","*I","*D","*R","*X","*Q" }; /*指令种类*/
int comlen = 6;
while (true) {
string com;
int c;
cout << "共有"<<len<<"行文本" << endl << "输入指令" << endl;
cin >> com;
bool p = true;
for (int i = 0; i < 6; i++) {
if (command[i] == com) { /*返回位置+1*/
c = i+1;
p = false;
break;
}
}
if (p) {
cout << "无效指令!" << endl; continue;
}
int m, n;
switch (c) {
case 1: {
while (true) {
cin >> m >> n;
if (m <= len && m >= 0 && n <= len && n >= 0 && m < n)break;
else cout << "m,n中存在的不合法数据,请重新输入!" << endl;
}
Node* p = begin;
for (int i = 0; i < m; i++) { /*直接输出*/
p = p->next;
}
for (int i = m; i <= n; i++) {
cout << p->s << endl;
p = p->next;
}
break;
}
case 2: {
while (true) {
cin >> m;
if (m <= len && m >= 0)break;
else cout << "m不合法,请重新输入!" << endl;
}
int kk = 1;
if (kk)getchar(); /*吞掉m后的回车*/
kk--;
Node* p = begin;
for (int i = 0; i < m; i++) {
p = p->next;
}
while (true) {
string txt;
while (true) {
char c;
c = getchar();
if (c != '\n')txt.push_back(c); /*不是回车就算在一个字符串里面*/
else break;
}
if (txt == "^Z")break;
len++;
Node* q = new Node(); /*插入结点*/
q->s = txt;
q->next = p->next;
p->next = q;
p = p->next;
}
break;
}
case 3: {
cin >> m >> n;
len -= (n - m + 1);
Node* p = begin;
for (int i = 0; i < m-1; i++) {
p = p->next;
}
Node* q = begin;
for (int i = 0; i < n; i++) {
q = q->next;
}
p->next = q->next; /*直接连接*/
break;
}
case 4: {
while (true) {
cin >> m >> n;
if (m <= len && m >= 0 && n <= len && n >= 0 && m < n)break;
else cout << "m,n中存在的不合法数据,请重新输入!" << endl;
}
int kk = 1;
if (kk == 1)getchar(); /*吞n后面的回车*/
kk--;
Node* p = begin;
for (int i = 0; i < m - 1; i++) {
p = p->next;
}
Node* p1 = begin;
for (int i = 0; i < n; i++) {
p1 = p1->next;
}
len -= (n - m + 1);
p->next = p1->next;
while (true) {
string txt;
kk--;
while (true) {
char c;
c = getchar();
if (c != '\n')txt.push_back(c); /*不是回车就算在一个字符串里面*/
else break;
}
if (txt == "^Z")break;
len++;
Node* q = new Node();
q->s = txt;
q->next = p->next;
p->next = q;
p = p->next;
}
break;
}
case 5: {
ofstream ofs;
ofs.open(file, ios::trunc); /*保存写入新链表*/
Node* p = begin->next;
while (p != NULL) {
ofs << p->s << endl;
p = p->next;
}
ofs.close();
return 0;
}
case 6: {
return 0; /*不保存*/
}
}
}
}
此程序涉及文件操作:
testpage.dat:
运行截图:
- 通过该实验对链表增删操作和文件读写有进一步理解。
- 难点还是链表操作,注意增加结点和删除节点时的赋值逻辑要正确。
- 自己对链表的操作能力有待更上一步,应该继续努力。