基於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]: ['刻舟求劍', '劍拔弩張', '張冠李戴', '戴憑奪席', '席豐履厚', '厚貌深情', '情恕理遣', '遣將調兵', '兵來將擋水來土掩', '掩耳不聞', '聞弦歌而知雅意']