C小项目——电子词典
C語言項目——查字典
宗旨:技術的學習是有限的,分享的精神是無限的。
【項目需求描述】
一、單詞查詢
給定文本文件“dict.txt”,該文件用于存儲詞庫。詞庫為“英-漢”,“漢-英”雙語詞典,每個單詞和其解釋的格式固定,如下所示:
#單詞
Trans:解釋1@解釋2@…解釋n
每個新單詞由“#”開頭,解釋之間使用“@”隔開。一個詞可能有多個解釋,解釋均存儲在一行里,行首固定以“Trans:”開頭。下面是一個典型的例子:
#abyssinian
Trans:a.?阿比西尼亞的@n.?阿比西尼亞人;依索比亞人
該詞有兩個解釋,一個是“a.?阿比西尼亞的”;另一個是“n.?阿比西尼亞人;依索比亞人”。
要求編寫程序將詞庫文件讀取到內存中,接受用戶輸入的單詞,在字典中查找單詞,并且將解釋輸出到屏幕上。用戶可以反復輸入,直到用戶輸入“exit”字典程序退出。
程序執行格式如下所示:
./app?–text
-text表示使用文本詞庫進行單詞查找。
二、建立索引,并且使用索引進行單詞查詢
要求建立二進制索引,索引格式如下圖所示。將文本文件“dict.txt”文件轉換為上圖所示索引文件“dict.dat”,使用索引文件實現單詞查找。程序執行格式如下:
./app?–index
-index表示使用文本詞庫dict.txt建立二進制索引詞庫dict.dat
./app?–bin
-bin表示使用二進制索引詞庫進行單詞查找。
//================================================================================================================
一、文本文件單詞查詢
1、單詞結構:
#單詞
Trans:解釋1@解釋2@…解釋n
在dict.txt文件中,單詞占一行,以“#”開頭;解釋以“Trans:”開頭,內容以“@”分隔。結構我采用鏈表。具體結構定義如下:
//?單詞鏈表?----?單詞名稱,翻譯的個數,單詞翻譯的結果
typedef?struct?dict
{
??char?word[TARGET_WORD_MAX_SIZE];?//?要輸入的單詞,如"#superstar"
??uint8_t?mean_count;??//?單詞解釋的個數,如既可以做名詞也可以做動詞,
??char?trans[TARGET_WORD_MEANING_COUNT][TARGET_WORD_MAX_TRANSLATION];?//?翻譯結果,用@分開(strtok分割函數)
??struct?dict?*next;
}?word_t,?*dict_t;
2、接口定義
2.1、文件中單詞的總數:要建立單鏈表,就要知道單鏈表的長度,因此,要知道文件中單詞的總個數,定義如下接口:
uint32_t?ListCount(FILE?*fp);?//?詞典里面單詞的個數,即是要創建鏈表的長度
2.2、創建單鏈表:從文件中一項一項讀出單詞及其解釋,填充到單詞結構體中,創建單鏈表就是分配內存并連接節點的過程,定義接口如下(count是單詞的總數):
dict_t?CreateList(dict_t?head,?FILE?*fp,?uint32_t?count);?//?創建單鏈表,返回首節點。分配內存。
2.3、查找單詞:從鏈表中匹配要查找的單詞,找到了就輸出單詞解釋,定義接口如下:
void?SearchList(dict_t?head,?uint32_t?count);?//?查找輸入的單詞
2.4、釋放內存:創建鏈表分配的內存在結束時釋放,定義接口如下:
void?DestroyList(dict_t?head);?//?釋放內存
二、建立索引文件dict.data
1、索引結構
如上圖所示,包含如下內容:索引頭單詞個數(4字節),單詞1的單詞長度(4字節),單詞1的內容(單詞長度個字節),單詞1的解釋個數(4字節),解釋1的長度(4字節),解釋1的內容(解釋1的長度),解釋2的長度(4字節),解釋2的內容(解釋2的長度)...按照這個格式將dict.txt文件的內容寫到dict.dat的索引文件中。結構和上面文本查詢的結構一樣。
2、接口定義
??將鏈表的節點按上面的格式一個一個寫到索引文件dict.dat中,用fwrite函數寫,定義接口如下:
//?鏈表頭結點head,文件名,鏈表長度
void?WriteIndexFile(dict_t?head,?const?char?*filename,?uint32_t?count);
三、索引文件查找單詞
上面建立了索引文件,并按協議的格式將文本文件的內容寫到了索引文件中,通過索引查找單詞就是從索引文件讀出要查找的單詞,用fread函數讀,接口定義如下:
void?ReadIndexFile(dict_t?head,?const?char?*filename,?uint32_t?*count);
具體實現:
#ifndef _TARGET_H_ #define _TARGET_H_#include <stdlib.h> #include <stdio.h> #include <string.h>typedef unsigned char uint8_t; typedef unsigned int uint32_t;#define TARGET_TEXT_NAME "./dict.txt" #define TARGET_INDEX_NAME "./dict.dat" #define TARGET_WORD_MAX_SIZE 60 #define TARGET_WORD_MEANING_COUNT 20 #define TARGET_WORD_MAX_TRANSLATION 100 #define TARGET_WORD_BUFFER 1024// 單詞鏈表 ---- 單詞名稱,單詞有幾種翻譯,單詞翻譯的結果 typedef struct dict {char word[TARGET_WORD_MAX_SIZE]; // 要輸入的單詞,如"#superstar"uint8_t mean_count; // 單詞解釋的個數,如既可以做名詞也可以做動詞,用@分開char trans[TARGET_WORD_MEANING_COUNT][TARGET_WORD_MAX_TRANSLATION]; // 翻譯結果struct dict *next; } word_t, *dict_t;uint32_t ListCount(FILE *fp); // 詞典里面單詞的個數,即是要創建鏈表的長度 dict_t CreateList(dict_t head, FILE *fp, uint32_t count); // 創建單鏈表,返回首節點。分配內存。 void SearchList(dict_t head, uint32_t count); // 查找輸入的單詞 void DestroyList(dict_t head); // 釋放內存void WriteIndexFile(dict_t head, const char *filename, uint32_t count); void ReadIndexFile(dict_t head, const char *filename, uint32_t *count);void Process(int argc, char **argv); // 主進程,main函數主要調用接口#endif /* _TARGET_H_ */main.c #include "target.h"int main(int argc, char **argv) {if(argc < 2){fprintf(stderr, "input params is too few!\n");return 1;}Process(argc, argv);return 0; }
process.c: #include "target.h"static const char params[][15] = {"-text", "-index", "-bin", "-test1 -f", "-test2 -f"};void Process(int argc, char **argv) {FILE *fp;dict_t head;uint32_t count;if((fp = fopen(TARGET_TEXT_NAME, "r")) == NULL){fprintf(stderr, "open file failure!\n");exit(1);}count = ListCount(fp);printf("count: %d\n", count);printf("open sucess!\n");if((strcmp(argv[1], params[0])) == 0){head = CreateList(head, fp, count);SearchList(head, count);fclose(fp);DestroyList(head);}if((strcmp(argv[1], params[1])) == 0){head = CreateList(head, fp, count);fclose(fp);WriteIndexFile(head, TARGET_INDEX_NAME, count);DestroyList(head);}if(strcmp(argv[1], params[2]) == 0){head = CreateList(head, fp, count);ReadIndexFile(head, TARGET_INDEX_NAME, &count);SearchList(head, count);fclose(fp);DestroyList(head);} }
find_word_from_text.c #include "target.h"static char file_exist;uint32_t ListCount(FILE *fp) // 單詞的個數即是鏈表的長度 {uint32_t count = 0;char buffer[100];while(fgets(buffer, sizeof(buffer), fp)){if('#' == buffer[0]){++count;}}rewind(fp); // 這一步一定要做,使文件指針指向文件頭return count; }dict_t CreateList(dict_t head, FILE *fp, uint32_t count) // 創建鏈表,返回頭結點 {dict_t new, pointer;char buf[TARGET_WORD_BUFFER];uint8_t word_size, trans_size, mean_count = 1, *str;uint32_t i, j = 0;head = (dict_t)malloc(sizeof(word_t)); //分配節點空間if(NULL == head){fprintf(stderr, "malloc failure!\n");exit(1);}printf("head success!\n");if(count > 0){memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), fp);word_size = strlen(buf);buf[word_size - 1] = '\0';strcpy(head->word, buf);memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), fp);trans_size = strlen(buf);buf[trans_size - 1] = '\0';str = strtok(buf, "@");strcpy(head->trans[j++], str + 6);while(str = strtok(NULL, "@")){strcpy(head->trans[j++], str);++mean_count;}head->mean_count = mean_count;head->next = NULL; // 到這里為止填充了首節點,并將首節點的下一個節點指向空pointer = head;for(i = 0; i < count - 1; ++i) // 將后面(count-1)個依次鏈接到首節點后面{mean_count = 1;new = (dict_t)malloc(sizeof(word_t)); //分配節點空間memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), fp);word_size = strlen(buf);buf[word_size - 1] = '\0';strcpy(new->word, buf);memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), fp);trans_size = strlen(buf);buf[trans_size - 1] = '\0';for(j = 0; j < count;){str = strtok(buf, "@");strcpy(new->trans[j++], str + 6);while(str = strtok(NULL, "@")){strcpy(new->trans[j++], str);++mean_count;}}new->mean_count = mean_count;new->next = NULL;pointer->next = new;pointer = new;}}rewind(fp);return head; }void PrintList(dict_t head) {dict_t pointer;pointer = head;while(pointer != NULL){printf("pointer->word = %s, pointer->mean_count = %d\n", pointer->word, pointer->mean_count);pointer = pointer->next;} }void SearchList(dict_t head, uint32_t count) // 從鏈表中查找單詞 {dict_t pointer;char str[TARGET_WORD_MAX_SIZE];uint32_t i;while(1){file_exist = 0;pointer = head;printf("Please input a word:");fgets(str, TARGET_WORD_MAX_SIZE, stdin);str[strlen(str) - 1] = '\0';if(strcmp(str, "exit") == 0){exit(1);}while(pointer != NULL){if((strcmp(pointer->word, str)) == 0){for(i = 0; i < pointer->mean_count; ++i){file_exist = 1;fprintf(stdout, "Trans%d: %s\n", i + 1, pointer->trans[i]);}break;}pointer = pointer->next;}if(file_exist == 0){ // 這里判斷了該單詞不存在,可以選擇添加,也可以選擇退出; /*printf("no find!\n");printf("Do you want to add a new word?:(Y/N)\n");scanf("%c", &new_word);if(new_word == 'Y' || new_word == 'y'){AddWordToText(head, TARGET_CUSTOM_TEXT);}*/exit(1);}} }void DestroyList(dict_t head) {dict_t pointer;while(pointer != NULL){pointer = head;head = head->next;free(pointer);} }
find_word_from_index.c #include "target.h"void WriteIndexFile(dict_t head, const char *filename, uint32_t count) // 建立索引,按協議格式寫入文件 {FILE *stream;uint32_t i, word_size, trans_size, mean_count;uint8_t j;dict_t pointer = head;if((stream = fopen(filename, "wb")) == NULL){fprintf(stderr, "Cannot open output file.\n");exit(1);}fwrite(&count, 4, 1, stream);while(pointer != NULL){word_size = strlen(pointer->word);mean_count = pointer->mean_count;fwrite(&word_size, 4, 1, stream);fwrite(pointer->word, 1, word_size, stream);fwrite(&mean_count, 4, 1, stream);for(j = 0; j < mean_count; ++j){trans_size = strlen(pointer->trans[j]);fwrite(&trans_size, 4, 1, stream);fwrite(pointer->trans[j], 1, trans_size, stream);}pointer = pointer->next;}fclose(stream); }void ReadIndexFile(dict_t head, const char *filename, uint32_t *count) // 從文件中讀出單詞內容 {FILE *stream;uint8_t i;uint32_t word_size, trans_size, mean_count;dict_t pointer = head;printf("enter...\n");if((stream = fopen(filename, "rb")) == NULL){fprintf(stderr, "Cannot open output file.\n");exit(1);}// printf("read file success!...\n");fread(count, 4, 1, stream);printf("count = %d\n", *count);while(pointer != NULL){fread(&word_size, 4, 1, stream);// printf("word_size = %d\n", word_size);fread(pointer->word, 1, word_size, stream);pointer->word[word_size] = '\0';fread(&pointer->mean_count, 4, 1, stream);//printf("pointer->word = %s\n", pointer->word);//printf("pointer->mean_count = %d\n", pointer->mean_count);for(i = 0; i < pointer->mean_count; ++i){memset(pointer->trans[i], 0, sizeof(pointer->trans[i]));fread(&trans_size, 4, 1, stream);fread(pointer->trans[i], 1, trans_size, stream);pointer->trans[i][trans_size] = '\0';printf("trans_size = %d\n", trans_size);printf("pointer->trans = %s\n", pointer->trans[i]);}pointer = pointer->next;}//fclose(stream);printf("read over!\n"); }
先用gcc編譯生成可執行文件app,再分別執行文本查詢,索引建立和索引查詢。
總結
以上是生活随笔為你收集整理的C小项目——电子词典的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STM32启动文件——startup_s
- 下一篇: html 抽签分小组代码,JavaScr