C語言實現(xiàn)簡易文本編輯器
本程序要求完成一個簡易文本編輯器,能夠完成文本的錄入、編輯、刪除、查找,并能夠完成文件的存取。
在文本編輯軟件中把用戶輸入的所有文本內(nèi)容作為一個字符串。雖然各種文本編輯軟件的功能有強弱差別,但是基本操作都包括串的輸入、修改、刪除(包括整行刪除和一行中的子串刪除)、查找、輸出等。通過分析,系統(tǒng)應該包括以下功能:
1、具有簡單的文字或圖形菜單界面
2、能實現(xiàn)串或文本塊的查找、替換、刪除、插入、移動操作。
3、能實現(xiàn)文本文件的存盤和讀取功能。
4、具有友好的界面和較強的容錯能力
設計思路
1、采用的邏輯結構
文本編輯器主要是針對文本進行編輯,文本的操作就是對字符的操作。文本編輯器可以從行、列兩個方向進行編輯。
每一行可以看成一個線性表,線性表是一種線性結構,線性結構的特點是數(shù)據(jù)元素之間為線性關系,數(shù)據(jù)元素“一個接一個的排列”。在一個線性表中數(shù)據(jù)元素的類型是相同的,由于每一行可以存儲的最大字數(shù)是相同的,行方向所有線性表的最大長度可以設置成相同的。行與行之間的關系也可以看成一個線性表。
2、采用的存儲結構
線性表的存儲分為兩種:順序存儲和鏈式存儲。
順序存儲是指在內(nèi)存中用地址連續(xù)的一塊存儲空間順序存放線性表的各元素,用這種存儲形式存儲的線性表稱為順序表。在程序設計語言中,一維數(shù)組在內(nèi)存中占用的存儲空間就是一組連續(xù)的存儲區(qū)域,因此,用一維數(shù)組來表示順序表的數(shù)據(jù)存儲區(qū)域是再合適不過的。
鏈式存儲是通過-組任意的存儲單元來存儲線性表中的數(shù)據(jù)元素的,為建立數(shù)據(jù)元系之間的線性關系,對每個數(shù)據(jù)元素除了存放數(shù)據(jù)元素自身的信息之外,還需要和一起存放其后繼或前驅所在的存儲單元的地址,這兩部分信息組成一個“結點”,每個元素都如此。存放數(shù)據(jù)元素信息的稱為數(shù)據(jù)域,存放其前驅或后繼地址的稱為指針域。只有一個存儲單元地址的為單鏈表,有兩個存儲單元地址的為雙鏈表。
考慮到實際的功能需求,每行的線性表可以用順序存儲方式,每個字符是一個節(jié)點。用數(shù)組的長度表示本行可以輸入的最大字符。行與行之間的線性表采用雙鏈表存儲,每個節(jié)點包括四個區(qū)域,一個指針域prior指向上一行,一個指針域next指向下一行,一個數(shù)據(jù)域num是行號,一個數(shù)據(jù)域是本行的字符數(shù)組。程序以行和列標識文本位置,行采用雙向鏈表存儲行信息,用數(shù)組下標標識列信息,從而能夠準確定位字符位置,然后進行查找、替換、插入、塊移動、刪除等多種操作。
#include<stdio.h> #include<stdlib.h> #include<string.h> #define MAX_LEN 100 #define NOT_FOUND -1 //定義行結構體: struct line { char text[MAX_LEN]; //本行文本 int num; //行號 struct line *next; //指向下一個行的指針 struct line *prior; //指向前一個行的指針 }; int lnum; struct line *start; //指向線性表中第一行的指針 struct line *last; //指向線性表中最后一行的指針 struct line *find(int); //查找指定行是否存在 void patchup(int, int); //對當前行以后的每行的行號加1或 void delete_text(int); //刪除一行文字 void list(); //顯示文件的全部內(nèi)容 void save(); //保存文件 void load(); //打開文件,初始化線性表 void insert(char str[], int linenum, int position); //插入文字到一行的中間 void printline(int linenum); //打印一行文字 void deletestr(int linenum, int position, int lenth); //刪除一個字符串 int findstr(char * to_find); //查找字符串 int menu_select(); //顯示主菜單 int menu_select_insert();//顯示插入功能子菜單 int menu_select_delete();//顯示刪除功能子菜單 int menu_select_print(); //顯示打印功能子菜單 int menu_select_move(); //顯示移動功能子菜單 void enter(int linenum); //插入一行文字 void enter_empty(int linenum); //插入一個空白行 //下列函數(shù)是系統(tǒng)主函數(shù),提供系統(tǒng)主界面,通過選擇項轉入執(zhí)行插入、刪除、查存盤、讀人文件等功能的界面。 int main(void) { char str[MAX_LEN]; int choice; int linenum = 1; int number = 0; start = NULL; last = NULL; load(); //打開文件,初始化線性表 do{ choice = menu_select(); switch (choice) { case 1: //執(zhí)行插入功能 choice = menu_select_insert();//顯示插入子菜單 switch (choice) { case 1: //插入一行 printf("\t行號:"); scanf("%d", &linenum); enter(linenum); break; case 2: //插入到指定行的指定列 printf("輸入插入位置一行號:"); scanf("%d", &linenum); printf("輸入插入位置-列號:"); scanf("%d", &number); printf("要插入的字符串:"); scanf("%s", str); insert(str, linenum, number); break; case 3: //退出插入 break; } break; case 2: //執(zhí)行刪除功能 choice = menu_select_delete(); // 刪除子菜單 switch (choice) { case 1: //刪除指定行 printf("\t行號:"); scanf("%d", &linenum); break; case 2: //刪除指定的字符串 printf("要刪除的字符串:"); scanf("%s", str); number = findstr(str); if (number == NOT_FOUND) printf("沒有找到"); else deletestr(lnum, number, strlen(str)); break; case 3: //退出刪除 break; } break; case 3: //執(zhí)行顯示功能 choice = menu_select_print(); //顯示子菜單 switch (choice) //顯示指定行 { case 1: printf("\t行號:"); scanf("%d", &linenum); printline(linenum); break; case 2: //顯示全部 list(); break; case 3: //退出顯示 break; } break; case 4: //執(zhí)行查找功能 printf("輸入想要查找的字符串:"); scanf("%s", str); number = findstr(str); if (number == NOT_FOUND) printf("沒有找到"); else printf("要查找的字符串所在行號:%d,列號:%d\n", lnum, number + 1); break; case 5: //執(zhí)行替換功能 printf("輸入被替換的字符串:"); scanf("%s", str); number = findstr(str); if (number == NOT_FOUND) printf("沒有找到"); else { deletestr(lnum, number, strlen(str)); printf("要替換的字符串:"); scanf("%s", str); insert(str, lnum, number + 1); } break; case 6: //執(zhí)行移動功能 choice = menu_select_move(); //移動子菜單 switch (choice) { case 1: // 向下移動一行 printf("輸人要移動的字符串所在行號:"); scanf("%d", &linenum); enter_empty(linenum); break; case 2: //向上移動一行 printf("輸入要移動的字符串所在行號:"); scanf("%d", &linenum); delete_text(linenum - 1); break; case 3: //向右移動一列 printf("輸人要移動的字符串所在行號:"); scanf("%d", &linenum); printf("輸入要移動的字符串所在列號:"); scanf("%d", &number); str[0] = ' '; str[1] = '\0'; insert(str, linenum, number); break; case 4: //向左移動 printf("輸入要移動的字符串所在行號:"); scanf("%d", &linenum); printf("輸入要移動的字符串所在列號:"); scanf("%d", &number); if (number <= 0) printf("該列不存在"); else deletestr(linenum, number - 2, 1); break; case 5: //退出移動 break; } break; case 7: //執(zhí)行存盤功能 save(); break; case 8: //執(zhí)行讀入文件功能 load(); break; case 9: //執(zhí)行退出功能 exit(0); break; } } while (1); return 0; } //下列函數(shù)是主菜單功能的提示界面,其功能是說明主菜單中選項 int menu_select() { int c; printf("\n\t\t1.插入\n"); printf("\t\t2.刪除\n"); printf("\t\t3.顯示\n"); printf("\t\t4.查找\n"); printf("\t\t5.替換\n"); printf("\t\t6.移動\n"); printf("\t\t7.文件存盤\n"); printf("\t\t8.裝入文件\n"); printf("\t\t9.退出\n"); do { printf("\n\n\t\t請按數(shù)字選擇:"); scanf("%d", &c); } while (!(c >= 1 && c <= 9)); return(c); } //下列函數(shù)是插入子菜單功能的提示界面,其功能是說明在插入菜單下選項的含義。 int menu_select_insert() { int c; printf("\n\t\t1.插入一行文字\n"); printf("\t\t2.插入一段文字\n"); printf("\t\t3.返回上級菜單\n"); do{ printf("\n\n\t\t請按數(shù)字選擇:"); scanf("%d", &c); } while (!(c >= 1 && c <= 3)); return(c); } //下列函數(shù)是刪除子菜單功能的提示界面,其功能是說明在刪除子菜單下選項的含義。 int menu_select_delete() { int c; printf("\n\t\t1.刪除一行文字\n"); printf("\t\t2.刪除一段文字\n"); printf("\t\t3.返回上級菜單\n"); do{ printf("\n\n\t\t請按數(shù)字選擇:"); scanf("%d", &c); } while (!(c >= 1 && c <= 3)); return(c); } //下列函數(shù)是顯示子菜單功能的提示界面,其功能是說明在顯示子菜單下選項的含義 int menu_select_print() { int c; printf("\n\t\t1.顯示一行\(zhòng)n"); printf("\t\t2.全部顯示\n"); printf("\t\t3.返回上級菜單\n"); do{ printf("\n\n\t\t請按數(shù)字選擇:"); scanf("%d", &c); }while(!(c >= 1 && c <= 3)); return(c); } //下列函數(shù)是移動子菜單功能的提示界面,其功能是說明在移動子菜單下選項的含義 int menu_select_move() { int c; printf("\n\t\t1.向下移動一行\(zhòng)n"); printf("\t\t2.向上移動一行\(zhòng)n"); printf("\t\t3.向右移動一列\(zhòng)n"); printf("\t\t4.向左移動一列\(zhòng)n"); printf("\t\t5.返回上級菜單\n"); do{ printf("\n\n\t\t請按數(shù)字選擇:"); scanf("%d", &c); } while (!(c >= 1 && c <= 5)); return(c); } //下列函數(shù)的功能是在指定的行號 linenum處插入一行文字。 void enter(int linenum) { struct line * info, * q, * p; p = start; q = NULL; while (p && p->num != linenum) //找到插入行 { q = p; p = p->next; } if (p == NULL && (q->num + 1) != linenum) //指定行不存在,不能插入 { printf("輸入的行號不存在"); } else // 指定行存在,進行插入 { info = (struct line *)malloc(sizeof(struct line)); printf("輸入要輸入的字符串"); scanf("%s", info->text); info->num = linenum; if (linenum == 1) //插入在第一行 { info->next = p; p->prior = info; info->prior = NULL; start = info; } else if (q->num != linenum) //插入在最后一行 { q->next = info; info->next = p; info->prior = q; } else //插入在其他行 { q->next = info; info->next = p; p->prior = info; info->prior = q; } while (p) //如果不是插入在最后一行,插入行后面的行號都加1 { p->num = p->num + 1; p = p->next; } } } //下列函數(shù)是為其他功能提供的一個輔助函數(shù),它的功能是當文本內(nèi)容插在文件中間時 //其下面的內(nèi)容的行號必須增加1,而刪除時,被刪除的文本后面的行號必減1. void patchup(int n, int incr) { struct line *i; i = find(n); i = i->next; while (i) { i->num = i->num + incr; i = i->next; } } //下列函數(shù)的功能是在指定行處插入一個空白行。 void enter_empty(int linenum) { struct line *info, *p; info = (struct line *)malloc(sizeof(struct line)); if (!info) { printf("\t!內(nèi)存不夠!\n"); exit(0); } info->text[0] = ' '; info->text[1] = '\0'; info->num = linenum; if (find(linenum)) //如果要插人的行號存在,則進行插入 { p = start; if (linenum == 1) //插入在首行 { info->next = p; start = info; info->prior = NULL; p->prior = info; } else //插入在其他行 { while (p->next->num != linenum) p = p->next; info->next = p->next; p->next->prior = info; p->next = info; info->prior = p; } patchup(linenum, 1); } else printf("該行不存在"); } //下列函數(shù)的功能是插入文字到一行的中間。要是插入位置和現(xiàn)有位置中間有間隔,會補全空格 void insert(char str[], int linenum, int position) { struct line * info; int len, i; int lenth; char rest_str[MAX_LEN], nostr[2] = { " " }; info = start; while (info && info->num != linenum) //查詢要插入的行 { info = info->next; } if (info == NULL) printf("不存在該行!\n"); else if (position < 0) printf("不存在該列!\n"); else //如果行和列都存在,則進行插入 { lenth = strlen(info->text); if (lenth < position) //插入列大于本行文件列數(shù) { len = position - lenth - 1; for (i = 0; i < len; i++) strcat(info->text, nostr); //將空余的部分插入空格符 strcat(info->text, str); //插入字符到列的未尾 } else //插入列在本行文字的中間 { strcpy(rest_str, &info->text[position - 1]); strcpy(&info->text[position - 1], str); strcat(info->text, rest_str); } } } //下列函數(shù)的功能是刪除指定行、指定位置、長度為 lenth的一段文字。 void deletestr(int linenum, int position, int lenth) { struct line * info; char rest_str[MAX_LEN]; info = find(linenum); if (info == NULL) printf("該行沒有字符!n"); else { if (strlen(info->text) <= (position + lenth)) //本行的字符長度<=待刪除的列號+刪除長度,直接在當前位置插入'\0' info->text[position] = '\0'; else { strcpy(rest_str, &info->text[position + lenth]); strcpy(&info->text[position], rest_str); } } } //下列函數(shù)的功能是刪除指定行號 lineup的文字。 void delete_text(int linenum) { struct line * info, *p; info = start; while ((info->num < linenum) && info) info = info->next; if (info->next == NULL) printf("該行不存在"); else { p = info->next; if (start == info) //如果刪除的是第一行 { start = info->next; if (start) //如果刪除后,不為空 start->prior = NULL; else //刪除后為空 last = NULL; } else { info->prior->next = info->next; //指定行的上一行指向指定行的下一行 if (info != last) //如果不是最后一行 info->next->prior = info->prior; //修改其下一行的指向頭的指針 else //如果是最后一行,修改尾指針 last = info->prior; } free(info); while (p) { p->num = p->num - 1; p = p->next; } } } //下列函數(shù)的功能是查找一段文字。 int findstr(char * to_find) { struct line * info; int i = 0, find_len, found = 0, position; char substring[MAX_LEN]; info = start; lnum = 0; //匹配到的行號 find_len = strlen(to_find); while (info && !found) //查詢 { i = 0; //行間循環(huán) while (!found && (i <= strlen(info->text) - find_len)) //行內(nèi)查找循環(huán) { strcpy(substring, &info->text[i], find_len); substring[find_len] = '\0'; if (strcmp(substring, to_find) == 0) { found = 1; lnum = info->num; } else ++i; } info = info->next; } if (found) //查找成功 position = i; else //查找不成功 position = NOT_FOUND; return(position); } //下列函數(shù)的功能是查找指定行,如果查找成功返回結點所在的行指針。 struct line * find(int linenum) { struct line * info; info = start; while (info) { if (linenum != info->num) info = info->next; else break; } return (info); } //下列函數(shù)的功能是顯示指定行 void printline(int linenum) { struct line *info; info = find(linenum); if (info) printf("%d:%s\n", info->num, info->text); else printf("該行不存在"); } //下列函數(shù)的功能是顯示線性表中的所有文本 void list() { struct line * info; info = start; while (info) { printf("%d:%s\n", info->num, info->text); info = info->next; } printf("\n\n"); } //下列函數(shù)的功能是把線性表中的所有文字保存到文件中 void save() { struct line * info; char * p; FILE * fp; if ((fp = fopen("D:\\text.txt", "w")) == NULL){ printf("\t文件打不開!n"); exit(0); } printf("\t正在存入文件!\n"); info = start; while (info) { p = info->text; while (*p) putc(*p++, fp); putc('\n', fp); info = info->next; } fclose(fp); } //下列函數(shù)的功能是把文本文件中的內(nèi)容讀入到線性表中。 void load() { struct line *info, *temp; //info指向當前行,temp指向info的前驅行 char c; FILE *fp; //文件指針 int inct, i; //行計數(shù)器 temp = NULL; if ((fp = fopen("D:\\text.txt", "r")) == NULL) { printf("\t文件打不開!\n"); exit(0); } printf("\n\t正裝入文件!\n"); start = (struct line*)malloc(sizeof(struct line)); //動態(tài)生成一行的結點空間 info = start; inct = 1; while ((c = fgetc(fp)) != EOF) { i = 0; info->text[i] = c; i++; while ((c = fgetc(fp)) != '\n') //從文件中讀取一行字符到線性表中,文件中每一行以\n為結束標 { info->text[i] = c; i++; } info->text[i] = '\0'; //線性表中每行末尾的結束標志 info->num = inct++; //行號和計數(shù)器都加1 info->next = (struct line*)malloc(sizeof(struct line)); if (!info->next) { printf("\n\t內(nèi)存已經(jīng)用完!"); exit(0); } info->prior = temp; temp = info; info = info->next; } temp->next = NULL; last = temp; free(info); start->prior = NULL; fclose(fp); }
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Qt利用QNetwork實現(xiàn)上傳數(shù)據(jù)的示例代碼
這篇文章主要為大家詳細介紹了Qt如何利用QNetwork實現(xiàn)上傳數(shù)據(jù)的 功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2023-02-02C++中string字符串分割函數(shù)split()的4種實現(xiàn)方法
最近筆試經(jīng)常遇到需要對字符串進行快速分割的情景,下面這篇文章主要給大家介紹了關于C++中string字符串分割函數(shù)split()的4種實現(xiàn)方法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-06-06