技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 137|回复: 3
收起左侧

【C】离线英英词典

[复制链接]

14

主题

19

回帖

426

积分

用户组: 中·技术宅

UID
6266
精华
5
威望
37 点
宅币
264 个
贡献
30 次
宅之契约
0 份
在线时间
19 小时
注册时间
2020-9-26
发表于 2023-1-23 02:00:55 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

x
本帖最后由 usr 于 2023-1-23 02:02 编辑

这是一款离线英英词典。该词典具有小内存占用和极高的查询速度。
原理很简单,搜索TXT格式的文件。把所有单词INDEX后装入内存。
源代码在这里:(注意该词典需要StoneValley库的支持)
[C] 纯文本查看 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "StoneValley/src/svset.h"
#include "StoneValley/src/svtree.h"

typedef struct st_WORD
{
	ptrdiff_t id;
	char name[64];
	size_t times;
	long ltip;
} WORD, * P_WORD;

int cbfcmpid(const void * px, const void * py)
{
	return (*(P_WORD)px).id - (*(P_WORD)py).id;
}

int cbfcmpchar(const void * px, const void * py)
{
	return *(char *)px - *(char *)py;
}

int cbftvs_history(void * pitem, size_t param)
{
	if (((P_WORD)P2P_TNODE_B(pitem)->pdata)->times)
		printf("%s\t%lld\n", ((P_WORD)P2P_TNODE_B(pitem)->pdata)->name, ((P_WORD)P2P_TNODE_B(pitem)->pdata)->times);
	return CBF_CONTINUE;
}

int cbftvs_alphabet(void * pitem, size_t param)
{
	if (toupper(((P_WORD)P2P_TNODE_B(pitem)->pdata)->name[0]) == param)
		printf("%s\n", ((P_WORD)P2P_TNODE_B(pitem)->pdata)->name);
	return CBF_CONTINUE;
}

static char sWord[BUFSIZ * 2] = { 0 };
static char * p = sWord;

static char sFileName[BUFSIZ] = { 0 };
static char sPattern[BUFSIZ] = { 0 };

int main(int argc, char ** argv)
{
	size_t i = 1, j;
	WORD w = { 0 };
	FILE * fp;
	P_SET_T set = setCreateT();
	P_TRIE_A trie = treCreateTrieA();
	size_t * result = NULL;

	strcat(sFileName, ".\\dict.txt");
	fp = fopen(sFileName, "rb");


	printf("Dict file: %s\n", sFileName);
	if (NULL != fp)
	{
		while (!feof(fp))
		{
			*p = fgetc(fp);
			++p;
			if ('#' == *(p - 1))
			{
				P_BSTNODE pnode = NULL;
				*(p - 1) = '\0';
				p = sWord;

				strcpy(w.name, p);
				w.id = i;
				w.times = 0;
				w.ltip = ftell(fp) + 1;

				setInsertT(set, &w, sizeof w, cbfcmpid);
				pnode = treBSTFindData_A(*set, &i, cbfcmpid);
				treInsertTrieA(trie, p, strlen(p), sizeof(char), (size_t)(pnode->knot.pdata), cbfcmpchar);

				++i;
			}
			if ('\n' == *(p - 1))
			{
				p = sWord;
			}
		}
		printf("%lld words loaded.\n", i);
		do
		{
			printf("? ");
			fgets(sPattern, 100, stdin);
			sPattern[strlen(sPattern) - 1] = '\0';
			if ('\0' == *sPattern)
				break;
			printf("Searching: \"%s\"...\n", sPattern);
			result = treSearchTrieA(trie, sPattern, strlen(sPattern), sizeof(char), cbfcmpchar);
			if (result)
			{
				printf("\t%lld %s  ", ((P_WORD)*result)->id, ((P_WORD)*result)->name);
				++((P_WORD)*result)->times;

				/* Redirect to the word on the disk. */
				fseek(fp, ((P_WORD)*result)->ltip, SEEK_SET);
				/* Read explanations. */
				p = sWord;
				while ('\n' != (*p = fgetc(fp)))
				{
					++p;
				}
				*p = '\0';
				p = sWord;
				printf("\t%s\n", p);
			}
			else if ('.' == sPattern[0] && '?' == sPattern[1])
			{
				printf("Type [WORD] or [NUMBER] to search.\n");
				printf("\tFor example ? Apple ? 10536\n");
				printf("Type .h to show history.\n");
				printf("Type .l[A] to show alphabet.\n");
				printf("\tFor example ? .l Z.\n");
				printf("Type .? to show this notice.\n");
			}
			else if ('.' == sPattern[0] && 'h' == sPattern[1])
			{
				printf("History:\n");
				treTraverseBIn(*set, cbftvs_history, 0);
			}
			else if ('.' == sPattern[0] && 'l' == sPattern[1] && ' ' == sPattern[2])
			{
				sPattern[3] = toupper(sPattern[3]);
				printf("Alphabet:\n");
				treTraverseBIn(*set, cbftvs_alphabet, toupper(sPattern[3]));
			}
			else if (0 != (j = atoi(sPattern)))
			{
				P_BSTNODE pnode = treBSTFindData_A(*set, &j, cbfcmpid);
				if (pnode)
				{
					printf("\t%lld %s  ", ((P_WORD)(pnode->knot.pdata))->id, ((P_WORD)(pnode->knot.pdata))->name);
					++((P_WORD)(pnode->knot.pdata))->times;

					/* Redirect to the word on the disk. */
					fseek(fp, ((P_WORD)(pnode->knot.pdata))->ltip, SEEK_SET);
					/* Read explanations. */
					p = sWord;
					while ('\n' != (*p = fgetc(fp)))
					{
						++p;
					}
					*p = '\0';
					p = sWord;
					printf("\t%s\n", p);
				}
			}
			else
			{
				printf("Can not find \"%s\".\n", sPattern);
			}
		} while ('\0' != sPattern[0]);
		fclose(fp);
	}
	else
		printf("Can not open file.\n");

	printf("History:\n");
	treTraverseBIn(*set, cbftvs_history, 0);
	setDeleteT(set);
	treDeleteTrieA(trie, sizeof(char));
	return 0;
}

运行截图如下:
Screenshot 2023-01-23 014707.png
Screenshot 2023-01-23 014752.png
这是词典的源码:欢迎下载
Dict.zip (1.9 MB, 下载次数: 0, 售价: 5 个宅币)
具体原理是将词典中的单词放在了平衡二叉搜索树和Trie树当中以方便查询。
回复

使用道具 举报

1099

主题

1600

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
242
威望
681 点
宅币
23204 个
贡献
46153 次
宅之契约
0 份
在线时间
2207 小时
注册时间
2014-1-26
发表于 2023-1-24 01:35:01 | 显示全部楼层
建议尝试脱离 StoneValley 库,看看能不能自己写出类似的算法,通过给定 index 进行快速的查询?

14

主题

19

回帖

426

积分

用户组: 中·技术宅

UID
6266
精华
5
威望
37 点
宅币
264 个
贡献
30 次
宅之契约
0 份
在线时间
19 小时
注册时间
2020-9-26
 楼主| 发表于 2023-1-25 14:53:13 | 显示全部楼层
0xAA55 发表于 2023-1-24 01:35
建议尝试脱离 StoneValley 库,看看能不能自己写出类似的算法,通过给定 index 进行快速的查询? ...

好的我试试看,但是离开SV库也只是在重复造轮子啊。会又写一个差不多的搜索树。

1099

主题

1600

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
242
威望
681 点
宅币
23204 个
贡献
46153 次
宅之契约
0 份
在线时间
2207 小时
注册时间
2014-1-26
发表于 2023-1-27 01:31:32 | 显示全部楼层
usr 发表于 2023-1-25 14:53
好的我试试看,但是离开SV库也只是在重复造轮子啊。会又写一个差不多的搜索树。 ...

如果不是以工作用为目标,而是以学习算法和数据结构为目标,那造轮子是很好的学习方式,是一定要试试的。

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2023-2-5 21:16 , Processed in 0.041132 second(s), 36 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表