C語言實現簡易文本編譯器
數據結構課程設計之簡易文本編譯器(C語言實現)
需求分析
(1)具有圖形菜單界面:顯示實時年份,日期,星期及時間
(2)
查找:查找文本中的字符串,顯示其出現的行數,列數及總共出現次數
替換(等長,不等長):對文本中的文本實現等長及不等長替換
插入(插串,文本塊的插入):插入一行或在具體行號列號處插入文本
塊移動(行塊,列塊移動):向下移動一行,向上移動一行,
具體行號列號處向左移動或向右移動
刪除:刪除一行,刪除莫一行,莫列,定長的內容
(3)可正確存盤、取盤;:可讀取,保存文本;
(4)正確顯示總行數。(行數不少於5行,每行字符數不少於80個字符)
采用的數據結構
1:采用的邏輯結構
文本編輯器主要是針對文本進行編輯,文本的操作就是對字符的操作。文本編輯器可以從行、
列兩個方向進行編輯。
每一行可以看成一個線性表,線性表是一種線性結構,線性結構的特點是數據元素之間為線性
關系,據元素“一個接一個的排列”。在一個線性表中數據元素的類型是相同的,由於每一行
可以存儲的最大字數是相同的,行方向所有線性表的最大長度可以設置成相同的。行與行之間
的關系也可以看成一個線性表。
2.采用的存儲結構
線性表的存儲分為兩種:順序存儲和鏈式存儲。
順序存儲是指在內存中用地址連續的一塊存儲空間順序存放線性表的各元素,用這種存儲形式
存儲的線性表稱為順序表。在程序設計語言中,一維數組在內存中占用的存儲空間就是一組連續
的存儲區域,因此,用一維數組來表示順序表的數據存儲區域是再合適不過的。
鏈式存儲是通過-組任意的存儲單元來存儲線性表中的數據元素的,為建立數據元系之間的線性
關系對每個數據元素除瞭存放數據元素自身的信息之外,還需要和一起存放其後繼或前驅所在的
存儲單元的地址,這兩部分信息組成一個“結點”,每個元素都如此。存放數據元素信息的稱為
數據域,存放其前驅或後繼地址的稱為指針域。隻有一個存儲單元地址的為單鏈表,有兩個存儲
單元地址的為雙鏈表。
考慮到實際的功能需求,每行的線性表可以用順序存儲方式,每個字符是一個節點。用數組的長
度表示本行可以輸入的最大字符。行與行之間的線性表采用雙鏈表存儲,每個節點包括四個區域,
一個指針域prior指向上一行,一個指針域next指向下一行,一個數據域num是行號,一個數據
域是本行的字符數組。程序以行和列標識文本位置,行采用雙向鏈表存儲行信息,用數組下標標識
列信息,從而能夠準確定位字符位置,然後進行查找、替換、插入、塊移動、刪除等多種操作。
函數功能模塊圖:
定義的結構體:
struct line { char text[MAX_LEN]; //本行的文本 int num; //行號 struct line *next; //指向下一行的指針 struct line *prior; //指向前一行的指針 };
代碼如下(僅供參考)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <math.h> #define MAX 240 #define NOT_FOUND -1 //函數聲明 void HeadWord(void); //輸出大標題,永遠出現在程序的最頂端。 void PrintWord(void); //輸出文本的內容 void printf_time(); //輸出時間和日期,星期及年月日 void scanf_load(); //從鍵盤錄入文本 void file_load(); //把文本文件的內容讀到線性表中 void findstr(); //查找字符串 void delete1(int linenum);//刪除一行 void delete2(int linenum,int position,int lenth);//刪除莫一行,莫列,定長的內容 void insert1(); // 插入一行文字 void insert2(char str[], int linenum, int position);//插入文字到文本莫一行莫一列 void replace(); //替換 void Mainmenu(); //主菜單 void menu1(); //文件錄入方式菜單 void menu2(); //文本內容處理菜單 void menu_move(); //移動菜單 //定義結構體 struct line { char text[MAX]; //該行的內容 int num; //用來記錄行號 struct line *prior; //用來指向前一行 struct line *next; //用來指向下一行 }; struct line *start; //指向線性表的第一行 struct line *last; //指向線性表的最後一行 //主函數 int main() { Mainmenu(); return 0; } //輸出標題,永遠出現在程序的最頂端。 void HeadWord() { printf("\t\t ____________________________________________________\n\n"); printf("\t\t**** Welcom to use our TXT edition system! ****\n"); printf("\t\t ____________________________________________________\n"); } // 輸出鏈表的內容 void PrintWord() { struct line *p = start; while(p != last) { printf("\n\t\t第%d行|%s",p->num,p->text); p = p->next; } printf("\n\t\t第%d行|%s",last->num,last->text); printf("\n"); } //輸出時間和日期 void printf_time() { time_t timep; struct tm *p; time (&timep); p=gmtime(&timep); //年月日 printf("\t\t|Data:%d-%d-%d |",1900+p->tm_year,1+p->tm_mon,p->tm_mday); //顯示星期幾 printf("Today is "); switch (p->tm_wday) { case 7: printf("Sunday |"); break; case 1: printf("Monday |"); break; case 2: printf("Tuesday |"); break; case 3: printf("Wednesday|"); break; case 4: printf("Thursday |"); break; case 5: printf(" Friday |"); break; case 6: printf("Saturday |"); break; default: break; } //讓時間固定顯示為 08:04:11類型,即當時,分,秒小於十時前加零 if(p->tm_hour+8<10&&p->tm_min>10&&p->tm_sec>10) printf("Time:0%d:%d:%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8<10&&p->tm_min<10&&p->tm_sec>10) printf("Time:0%d:0%d:%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8<10&&p->tm_min<10&&p->tm_sec<10) printf("Time:0%d:0%d:0%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8>=10&&p->tm_min<10&&p->tm_sec<10) printf("Time:%d:0%d:0%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8>=10&&p->tm_min>=10&&p->tm_sec<10) printf("Time:%d:%d:0%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8>=10&&p->tm_min>=10&&p->tm_sec>=10) printf("Time:%d:%d:%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8>=10&&p->tm_min<10&&p->tm_sec>=10) printf("Time:%d:0%d:%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8<10&&p->tm_min>=10&&p->tm_sec<10) printf("Time:0%d:%d:0%d |",p->tm_hour+8,p->tm_min,p->tm_sec); } //把文本文件的內容讀到線性表中 void file_load() { struct line *info,*temp; //行指針,info指向當前行,temp指向info的前驅行 char ch; temp = NULL; int linenum,i; //行計數器,行字符數組下標 FILE *fp; //文件指針 char name[20]; printf("請輸入要打開文件名字(例如c:\\a.txt)"); scanf("%s",name); while ((fp=fopen(name,"r"))==NULL) { printf("\n打開文件失敗,請重新輸入要打開的文件名:"); scanf("%s",name); } start = (struct line*)malloc(sizeof(struct line)); //生成一行的結點空間 info = start; linenum = 1; while((ch = fgetc(fp)) != EOF) { i = 0; info->text[i] = ch; i++; while((ch = fgetc(fp)) != '\n') //從文件中讀到一行字符到線性表中 { info->text[i] = ch; i++; } info->num = linenum++; info->next = (struct line*)malloc(sizeof(struct line)); if (!info->next) { printf("\n\t\t內存不足"); getchar(); exit(0); } temp = info; info = info->next; info->prior = temp; } last = info->prior; printf("\t\t文件讀入完畢\n"); fclose(fp); } //從鍵盤錄入文本 void scanf_load() { struct line *info,*temp; //行指針,info指向當前行,temp指向info的前驅行 char ch; temp = NULL; int linenum,i; //行計數器,行字符數組下標 FILE *fp; //文件指針 temp = NULL; start = (struct line*)malloc(sizeof(struct line)); //生成一行的結點空間 info = start; linenum = 1; printf("\t\t請從鍵盤錄入文本(輸入時回車換行,輸入結束後在新的一行輸入#結束錄入)\n\t\t"); while((ch = getchar()) !='#') { i = 0; info->text[i] = ch; i++; while((ch = getchar()) != '\n') //從文件中讀到一行字符到線性表中 { info->text[i] = ch; i++; } printf("\t\t"); info->text[i] = '\0'; info->num = linenum++; info->next = (struct line*)malloc(sizeof(struct line)); if (!info->next) { printf("\n\t\t內存不足"); getchar(); exit(0); } info->prior = temp; temp = info; info = info->next; } temp->next = NULL; last = temp; free(info); start->prior = NULL; } //文件保存 void save() { system("cls"); FILE *fp; line *info=start; int i=0; char name[20]; printf("\n請輸入保存地址(例如: c:\\a.txt):"); scanf("%s",name); while ((fp=fopen(name,"w+"))==NULL) { printf("文件不存在,請重新輸入文件名:"); scanf("%s",name); } while(info) { while(info->text[i]!='\n') {fprintf(fp,"%c",info->text[i]); i++; } info = info->next; i = 0; } fclose(fp); printf("\n文件保存成功\n"); } //查找字符串 void findstr(){ PrintWord(); char str[MAX]; getchar(); printf("\t\t 輸入想要查找的字符串:"); gets(str); printf("\t\t|>>________________________________________________<<|\n"); struct line *info; int i = 0, find_len, found = 0, position; char substring[MAX]; info = start; int find_num = 0; //匹配到的次數 find_len = strlen(str); while (info) //查詢 { i = 0; //行間循環 while (i <= (strlen(info->text) - find_len)) //行內查找循環 { int k=0; for(int j=i;j<i+find_len;j++) // 行內的字符串從第一個開始按定長find_len賦給substring { substring[k] = info->text[j]; k++; } if (strcmp(substring,str) == 0) { find_num++; printf("\t\t|第%d次出現在:%d行%d列\n",find_num,info->num,(i+1+1)/2); found = 1; } i++; } info = info->next; } if (found) //查找成功 printf("\t\t|\t\t該內容出現的總次數為%d\n",find_num); else //查找不成功 printf("\t\t該內容不存在\n"); printf("\t\t|>>________________________________________________<<|\n"); } //刪除一行 void delete1(int line_num) { struct line * info, *p; info = start; while ((info->num < line_num) && info) //尋找要刪除的行 info = info->next; if (info == 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; } } } //刪除莫一行,莫列,定長的內容 void delete2(int line_num,int position,int lenth) { struct line *info=start; char rest_str[MAX]; if(line_num == 1) info = start; else for(int i=1;i<line_num;i++) //讓info指向刪除內容所在行 info = info->next; if (info == NULL) printf("該行沒有字符!n"); else { if (strlen(info->text) <= (position + lenth)) //本行的字符長度<=待刪除的列號+刪除長度,直接在當前位置插入'\0' info->text[position] = '\0'; else { int i; for(i = position-1;info->text[i+lenth]!='\0';i++) info->text[i]=info->text[i+lenth]; info->text[i]='\0'; } } } // 插入一行文字 void insert1() { int linenum; printf("\t\t輸入插入位置的行號:"); scanf("%d", &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("\t\t輸入的行號不存在"); } else // 指定行存在,進行插入 { info = (struct line *)malloc(sizeof(struct line)); printf("\t\t輸入要插入的字符串:"); 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; } } } //插入文字到文本莫一行莫一列 void insert2(char str[], int linenum, int position) { struct line * info; int len, i; int lenth; char rest_str[MAX],kongge[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) //插入列大於本行文件列數 { len = position - lenth - 1; for (i = 0; i < len; i++) strcat(info->text, kongge); //將空餘的部分插入空格符 strcat(info->text, str); //插入字符到列的未尾 } else //插入列在本行文字的中間 { strcpy(rest_str, &info->text[position - 1]); strcpy(&info->text[position - 1], str); strcat(info->text, rest_str); } } } //替換 void replace() { PrintWord(); char str[MAX]; printf("\t\t輸入想要替換的字符串:\t\t"); scanf("%s",&str); char replace[MAX]; printf("\t\t替換為:"); scanf("%s",&replace); struct line *info; int i = 0, find_len, found = 0, position; char bijiao[MAX]; info = start; int find_num = 0; //匹配到的次數 find_len = strlen(str); while (info) //查詢 { i = 0; //行間循環 while (i <= (strlen(info->text) - find_len)) //行內查找循環 { int k=0; for(int j=i;j<i+find_len;j++) // 行內的字符串從第一個開始按定長find_len賦給substring { bijiao[k] = info->text[j]; k++; } if (strcmp(bijiao,str) == 0) { find_num++; delete2(info->num,i+1,find_len); insert2(replace,info->num,i+1); found = 1; } i++; } info = info->next; } if (found) //查找成功 printf("\t\t該內容替換的總次數為%d\n",find_num); else //查找不成功 printf("\t\t該內容不存在\n"); printf("\t\t經過替換後的內容為:\n"); PrintWord(); } //文件錄入方式菜單 void menu1() { printf("\t\t|請選擇錄入方式 1:從鍵盤輸入 2:從文件錄入 |\n\t\t"); int i; scanf("%d",&i); getchar(); if(i>2||i<1) { printf("\t\t對不起,請輸入正確的功能序號!\n"); } switch(i) { case 1: scanf_load(); system("cls"); break; case 2: file_load(); system("cls"); break; } } //移動菜單 void menu_move() { int choice; printf("\n\t\t|_____________________移動操作_______________________|\n"); printf("\n\t\t|----->1. 向下移動一行 <-----------|\n"); printf("\t\t|----->2. 向上移動一行 <-----------|\n"); printf("\t\t|----->3. 向右移動一列 <-----------|\n"); printf("\t\t|----->4. 向左移動一列 <-----------|\n"); printf("\t\t|----->5. 返回上級菜單 <-----------|\n"); printf("\t\t請選擇"); scanf("%d",&choice); int line_num,number; char str[2]; switch (choice) { case 1: // 向下移動一行 printf("\t\t輸人要移動的字符串所在行號:"); scanf("%d", &line_num); struct line *info,*p; //新建一行空行 info = (struct line *)malloc(sizeof(struct line)); info->text[0] = ' '; info->text[1] = '\0'; info->num = line_num; if (line_num == 1) //插入在首行 { info->next = start; start->prior = info; start = info; start->prior = NULL; p=start->next; } else //插入在其他行 { p=start; while (p->num != line_num) p = p->next; //令p指向插入行 info->next=p; info->prior=p->prior; p->prior->next=info; p->prior = info;} while (p) //插入行後面的行號都加1 { p->num = p->num + 1; p = p->next; } break; case 2: //向上移動一行 printf("\t\t輸入要移動的字符串所在行號:"); scanf("%d",&line_num); delete1(line_num-1); break; case 3: //向右移動一列 printf("\t\t輸人要移動的字符串所在行號:"); scanf("%d", &line_num); printf("\t\t輸入要移動的字符串所在列號:"); scanf("%d", &number); str[0] = ' '; str[1] = '\0'; insert2(str, line_num, number); break; case 4: //向左移動 printf("\t\t輸入要移動的字符串所在行號:"); scanf("%d", &line_num); printf("\t\t輸入要移動的字符串所在列號:"); scanf("%d", &number); if (number <= 0) printf("\t\t該列不存在"); else delete2(line_num, number - 2, 1); break; case 5: //退出移動 break; } } //文本內容處理菜單 void menu2() { char str1[20]; char str2[20]; int a; do { HeadWord(); printf_time(); printf("\n\t\t ____________________________________________________\n"); printf("\t\t| 文章內容處理菜單 |\n"); printf("\t\t|____________________________________________________|\n"); printf("\t\t|----> 1、查找文章中的字符或者字符串 |\n"); printf("\t\t|----> 2、刪除文章中的字符或者字符串 |\n"); printf("\t\t|----> 3、向文章中插入字符或者字符串 |\n"); printf("\t\t|----> 4、移動文章字符或字符串 |\n"); printf("\t\t|----> 5、替換文章字符或字符串 |\n"); printf("\t\t|----> 6、返回主菜單 |\n"); printf("\t\t|----> 7、直接退出系統 |\n"); printf("\t\t|____________________________________________________|\n"); printf("\t\t 請選擇:"); scanf("%d",&a); switch(a) { case 1: system("cls"); HeadWord(); findstr(); printf("\t\t按回車鍵繼續·····"); getchar(); getchar(); system("cls"); break; case 2: system("cls"); HeadWord(); printf("\t\t| 1:刪除一行文字 2:刪除莫一行,莫列,定長的內容|\n\t\t"); int delete_choice; scanf("%d",&delete_choice); getchar(); if(delete_choice == 1) { int linenum; printf("\t\t當前文本為:\n"); PrintWord(); printf("\t\t請輸入你刪除行的行號:"); scanf("%d",&linenum); getchar(); delete1(linenum); } else if(delete_choice == 2) { int linenum, position,lenth; //行,列,刪除長度 printf("\t\t當前文本為:\n"); PrintWord(); printf("\t\t請輸入要刪除內容所在行,列,刪除內容字節長度,中間用空格隔開\n"); printf("\t\t--->註意:漢字占兩個字節\n\t\t"); scanf("%d %d %d",&linenum,&position,&lenth); position = (position*2)-1; getchar(); delete2(linenum,position,lenth); } printf("\t\t刪除後的文章為:\n"); PrintWord(); printf("\t\t按回車鍵繼續·····"); getchar(); getchar(); system("cls"); break; case 3: system("cls"); HeadWord(); printf("\t\t| 1:插入一行文字 2:插入文字到文本到一行的中間|\n\t\t"); int insert_choice; scanf("%d",&insert_choice); if(insert_choice == 1) { printf("\t\t當前文本為:\n"); PrintWord(); insert1();} else { printf("\t\t當前文本為:\n"); PrintWord(); char str[MAX]; int linenum; int position; printf("\t\t輸入插入位置一行號:"); scanf("%d", &linenum); printf("\t\t輸入插入位置-列號:"); scanf("%d", &position); position = (position*2)-1; printf("\t\t要插入的字符串:"); scanf("%s", str); insert2(str,linenum,position); } printf("\t\t插入字符或字符串後文章為:\n"); PrintWord(); printf("\t\t按回車鍵繼續·····"); getchar(); getchar(); system("cls"); break; case 4: system("cls"); HeadWord(); printf_time(); menu_move(); printf("\t\t移動後文本內容為:\n"); PrintWord(); printf("\t\t按回車鍵繼續·····"); getchar(); getchar(); system("cls"); break; case 5: system("cls"); HeadWord(); printf_time(); replace(); printf("\t\t按回車鍵繼續·····"); getchar(); getchar(); system("cls"); break; } if(a==6) { system("cls"); break; } if(a==7) exit(0); }while(1); } //主菜單 void Mainmenu() { printf("\n\n\n\n\n\n\n\n\n\t\t\tWelcom to use our TXT edition system!\n"); printf("\n\n\t\t\t 歡迎您使用簡易文本編輯器!\n"); printf("\n\n\n\n\n\n\n\n\npress Enter to continue..."); getchar(); system("cls"); int t; do{ HeadWord(); printf_time(); printf("\n"); printf("\t\t ____________________________________________________\n"); printf("\t\t| 主菜單 |\n"); printf("\t\t| |\n"); printf("\t\t|----> 1、輸入文章內容 |\n"); printf("\t\t|----> 2、進入文章內容處理菜單 |\n"); printf("\t\t|----> 3、顯示當前文章內容 |\n"); printf("\t\t|----> 4、保存文本 |\n"); printf("\t\t|----> 5、退出文本編輯器 |\n"); printf("\t\t| |\n"); printf("\t\t| 註:第一次運行本程序時請選擇功能1 |\n"); printf("\t\t|____________________________________________________|\n"); printf(" \t\t 請選擇:"); scanf("%d",&t); if(t>5||t<1) { printf("對不起,無此功能,請輸入正確的功能序號!\n"); } else switch(t) { case 1: system("cls"); HeadWord(); menu1(); printf("\t\t按回車鍵繼續·····"); getchar(); getchar(); system("cls"); break; case 2: system("cls"); menu2(); break; case 3: system("cls"); HeadWord(); printf_time(); printf("\n\t\t ____________________文章內容為______________________\n"); PrintWord(); printf("\n"); printf("\t\t按回車鍵繼續·····"); getchar(); getchar(); system("cls"); break; case 4: HeadWord(); save(); break; } if(t==5) break; }while(1); }
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。