基于Python经典版成语接龙逻辑实现
今天,想检验一下前期Python学习成功,加上好友提起斗一波成语接龙,为完全碾压,轻松取胜,便顺手写一个适合日常群聊PK的成语接龙小程序。具体实现流程如下:
成语俗语词库下载
前往搜狗输入法官网,找到词库页面,搜索成语,定位进入 成语俗语 页面, 下载 官方词库 -- 成语俗语【官方推荐】.scel
搜狗成语俗语词库转txt备用
github上有现成的scel转txt的代码,此处个人调试为适用python3.6的版本
import struct import os # 搜狗的scel词库就是保存的文本的unicode编码,每两个字节一个字符(中文汉字或者英文字母) # 找出其每部分的偏移位置即可 # 主要两部分 # 1.全局拼音表,貌似是所有的拼音组合,字典序 # 格式为(index,len,pinyin)的列表 # index: 两个字节的整数 代表这个拼音的索引 # len: 两个字节的整数 拼音的字节长度 # pinyin: 当前的拼音,每个字符两个字节,总长len # # 2.汉语词组表 # 格式为(same,py_table_len,py_table,{word_len,word,ext_len,ext})的一个列表 # same: 两个字节 整数 同音词数量 # py_table_len: 两个字节 整数 # py_table: 整数列表,每个整数两个字节,每个整数代表一个拼音的索引 # # word_len:两个字节 整数 代表中文词组字节数长度 # word: 中文词组,每个中文汉字两个字节,总长度word_len # ext_len: 两个字节 整数 代表扩展信息的长度,好像都是10 # ext: 扩展信息 前两个字节是一个整数(不知道是不是词频) 后八个字节全是0 # # {word_len,word,ext_len,ext} 一共重复same次 同音词 相同拼音表 # 拼音表偏移, startPy = 0x1540; # 汉语词组表偏移 startChinese = 0x2628; # 全局拼音表 GPy_Table = {} # 解析结果 # 元组(词频,拼音,中文词组)的列表 GTable = [] # 原始字节码转为字符串 def byte2str(data): pos = 0 str = \'\' while pos < len(data): c = chr(struct.unpack(\'H\', bytes([data[pos], data[pos + 1]]))[0]) if c != chr(0): str += c pos += 2 return str # 获取拼音表 def getPyTable(data): data = data[4:] pos = 0 while pos < len(data): index = struct.unpack(\'H\', bytes([data[pos],data[pos + 1]]))[0] pos += 2 lenPy = struct.unpack(\'H\', bytes([data[pos], data[pos + 1]]))[0] pos += 2 py = byte2str(data[pos:pos + lenPy]) GPy_Table[index] = py pos += lenPy # 获取一个词组的拼音 def getWordPy(data): pos = 0 ret = \'\' while pos < len(data): index = struct.unpack(\'H\', bytes([data[pos], data[pos + 1]]))[0] ret += GPy_Table[index] pos += 2 return ret # 读取中文表 def getChinese(data): pos = 0 while pos < len(data): # 同音词数量 same = struct.unpack(\'H\', bytes([data[pos], data[pos + 1]]))[0] # 拼音索引表长度 pos += 2 py_table_len = struct.unpack(\'H\', bytes([data[pos], data[pos + 1]]))[0] # 拼音索引表 pos += 2 py = getWordPy(data[pos: pos + py_table_len]) # 中文词组 pos += py_table_len for i in range(same): # 中文词组长度 c_len = struct.unpack(\'H\', bytes([data[pos], data[pos + 1]]))[0] # 中文词组 pos += 2 word = byte2str(data[pos: pos + c_len]) # 扩展数据长度 pos += c_len ext_len = struct.unpack(\'H\', bytes([data[pos], data[pos + 1]]))[0] # 词频 pos += 2 count = struct.unpack(\'H\', bytes([data[pos], data[pos + 1]]))[0] # 保存 GTable.append((count, py, word)) # 到下个词的偏移位置 pos += ext_len def scel2txt(file_name): print(\'-\' * 60) with open(file_name, \'rb\') as f: data = f.read() print("词库名:", byte2str(data[0x130:0x338])) # .encode(\'GB18030\') print("词库类型:", byte2str(data[0x338:0x540])) print("描述信息:", byte2str(data[0x540:0xd40])) print("词库示例:", byte2str(data[0xd40:startPy])) getPyTable(data[startPy:startChinese]) getChinese(data[startChinese:]) if __name__ == \'__main__\': # scel所在文件夹路径 in_path = "E:\python_workspace" # 输出词典所在文件夹路径 out_path = "coal_dict.txt" fin = [fname for fname in os.listdir(in_path) if fname[-5:] == ".scel"] for f in fin: f = os.path.join(in_path, f) scel2txt(f) # 保存结果 with open(out_path, \'w\', encoding=\'utf8\') as f: f.writelines([word+\'\n\' for count, py, word in GTable])
业务逻辑实现
from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = "all" from pypinyin import pinyin, lazy_pinyin, Style idiom_dic = {} idiom_list = [] idiom_char_dic = {} with open(\'E:\python_workspace\coal_dict.txt\', \'r\', encoding=\'utf8\') as r: for line in r: line = line.strip() if None == line or line == \'\': continue idiom_list.append(line) key = lazy_pinyin(line)[0] value = \'\' if key in idiom_dic.keys(): value = idiom_dic[key] + \',\' + line else: value = line idiom_dic[key] = value # 汉字接龙 key_char = line[0] value_char = \'\' if key_char in idiom_char_dic.keys(): value_char = idiom_char_dic[key_char] + \',\' + line else: value_char = line idiom_char_dic[key_char] = value_char # 汉字接龙,polyphone -- 是否匹配读音 def idiom_next_char(idiom, polyphone=False): if idiom not in idiom_list: res = idiom + \' is not one idiom\' else: last = idiom[len(idiom) - 1] if polyphone: pass if last not in idiom_char_dic: res = \'library without the supply idioms\' else: aa = idiom_char_dic[last] last = lazy_pinyin(idiom)[len(idiom) - 1] bb = idiom_dic[last] aa_list = aa.split(\',\') bb_list = bb.split(\',\') cd_list = set(aa_list).intersection(set(bb_list)) # 求并集 res = \',\'.join(cd_list) else: if last not in idiom_char_dic: res = \'library without the supply idioms\' else: res = idiom_char_dic[last] return res # 拼音接龙 def idiom_next(idiom): if idiom not in idiom_list: res = idiom + \' is not one idiom\' else: last = lazy_pinyin(idiom)[len(idiom) - 1] if last not in idiom_dic: res = \'library without the supply idioms\' else: res = idiom_dic[last] return res # print(idiom_next(\'怒发冲冠\')) # 汉字定长接龙 def idiom_multi_char_length(idiom, length=10, polyphone=False): index = 0 res_list = [idiom] while index < length: res = idiom_next_char(idiom, polyphone) if \'idiom\' in res: break else: res_next = res.split(\',\') idiom = res_next[0] res_list.append(idiom) index = index + 1 return res_list # 拼音定长接龙 def idiom_multi_length(idiom, length=10): index = 0 res_list = [idiom] while index < length: res = idiom_next(idiom) if \'idiom\' in res: break else: res_next = res.split(\',\') idiom = res_next[0] res_list.append(idiom) index = index + 1 return res_list def check_none_follow_list(): none_follow = [] for idiom in idiom_list: res = idiom_next(idiom) if \'idiom\' in res: none_follow.append(idiom) return none_follow # none_supply = check_none_follow_list() # print(none_supply)
简单调试
pycharm 2018.2版本依赖,支持 运行调试功能,即即直接加载 .py 代码到内存,可以直接调用声明的函数和变量,打开方式:Run/Debug Configurations -- Configuration -- Execution -- Run with Python console。
这样调试尤其便利:
1、成语接龙(读音匹配)
idiom_multi_length(\'刻舟求剑\') Out[6]: [\'刻舟求剑\', \'兼爱无私\', \'死败涂地\', \'低昂不就\', \'灸艾分痛\', \'同胞共气\', \'期月有成\', \'撑岸就船\', \'传杯换盏\', \'粘皮带骨\', \'告朔饩羊\']
2、成语接龙(汉字匹配)
idiom_multi_char_length(\'刻舟求剑\') Out[5]: [\'刻舟求剑\', \'剑拔弩张\', \'张本继末\', \'末大必折\', \'折本买卖\', \'卖卜测字\', \'字挟风霜\', \'霜刀小径\', \'径情而行\', \'行行出状元\', \'元恶大憝\']
3、成语接龙(汉字、读音匹配)
idiom_multi_char_length(\'刻舟求剑\',polyphone=True) Out[7]: [\'刻舟求剑\', \'剑拔弩张\', \'张冠李戴\', \'戴凭夺席\', \'席丰履厚\', \'厚貌深情\', \'情恕理遣\', \'遣将调兵\', \'兵来将挡水来土掩\', \'掩耳不闻\', \'闻弦歌而知雅意\']