1. 程式人生 > >Python讀取scel檔案

Python讀取scel檔案

背景介紹:將搜狗詞庫中 .scel 檔案轉化為 .txt 檔案

  1. 搜狗詞庫連結:https://pinyin.sogou.com/dict/
  2. 搜狗的scel詞庫就是儲存的文字的unicode編碼,每兩個位元組一個字元(中文漢字或者英文字母)找出其每部分的偏移位置即可,主要兩部分:

    2.1 全域性拼音表,貌似是所有的拼音組合,字典序 格式為(index,len,pinyin)的列表 index: 兩個位元組的整數 代表這個拼音的索引 len: 兩個位元組的整數 拼音的位元組長度 pinyin: 當前的拼音,每個字元兩個位元組,總長len

    2.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次 同音詞 相同拼音表
  3. struct函式 -- struct.pack()和struct.unpack()

    在轉化過程中,主要用到了一個格式化字串(format strings),用來規定轉化的方法和格式。

    3.1 struct.pack(fmt,v1,v2,.....)

      將v1,v2等引數的值進行一層包裝,包裝的方法由fmt指定。被包裝的引數必須嚴格符合fmt。最後返回一個包裝後的字串。

    3.2 struct.unpack(fmt,string)

      顧名思義,解包。比如pack打包,然後就可以用unpack解包了。返回一個由解包資料(string)得到的一個元組(tuple), 即使僅有一個數據也會被解包成元組。其中len(string) 必須等於 calcsize(fmt),這裡面涉及到了一個calcsize函式。struct.calcsize(fmt):這個就是用來計算fmt格式所描述的結構的大小。 格式字串(format string)由一個或多個格式字元(format characters)組成,對於這些格式字元的描述參照Python manual如下:

Format C Type Python
x pad byte no value
c char string of length
b signed char integer
B unsigned char integer
h short integer
H unsigned short integer
i int integer
I unsigned int long
l long integer
L unsigned long long
q long long long
Q unsigned long long long
f float float
d double float
s char[] string
p char[] string
P void * integer

下面給出 Python 程式碼:


import struct
import os

# 拼音表偏移,
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 = "Scel"

    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)
        
    f = open('./Scel/coal_dict.txt', 'w')
    for count, py, word in GTable:
        f.write(str(count)+ '\t\t\t' + py + '\t\t\t' + word + '\n')
    f.close()

得到結果如下:

 

------------------------------------------------------------
詞庫名: 東北話大全【官方推薦】
詞庫型別: 方言
描述資訊: 賊拉逗的東北話你一定聽過,說起來實在霸氣!詞庫終於出來了,再也不愁打不出來你想說的話,專門為你私人訂製哦,還不快去下載!!!
詞庫示例: 不想嘎哈 老嘎瘩 嗯吶 瞅你咋的 咋地  
------------------------------------------------------------
詞庫名: 史記【官方推薦】
詞庫型別: 文學
描述資訊: 作者司馬遷以其“究天人之際,通古今之變,成一家之言”的史識,使《史記》成為中國第一部,也是最出名的紀傳體通史。小編整理了書中經典故事、名句、人物等,讓你更快打出相關詞彙,我在這等你哦~
詞庫示例: 十表 姬昌 項羽本紀 武王伐紂 虛懷若谷 商鞅變法 
------------------------------------------------------------
詞庫名: 開發大神專用詞庫【官方推薦】
詞庫型別: 網際網路
描述資訊: 程式猿們是不是遨遊在程式碼的海洋裡無法自拔?小編知道你們整日找BUG辛苦了,為輔助你們的工作特意奉上專屬詞庫,提高工作效率,暢快打字。歡迎你們前來補充詞條哦 !
詞庫示例: 資源保留 程式碼 優先順序 啟動事件 排期 公開測試 
------------------------------------------------------------
詞庫名: 柳宗元詩詞【官方推薦】
詞庫型別: 詩詞歌賦
描述資訊: 柳宗元,唐朝文學家、散文家和思想家。倡導唐代古文運動。散文論說性強,筆鋒犀利,諷刺辛辣。遊記寫景狀物,多所寄託。詩多抒寫抑鬱悲憤、思鄉懷友之情,自成一路。
詞庫示例: 柳河東 永州八記 捕蛇者說 柳河東集 江雪 小石潭記 
------------------------------------------------------------
詞庫名: 詩經【官方推薦】
詞庫型別: 詩詞歌賦
描述資訊: 《詩經》是中國古代詩歌開端,最早的一部詩歌總集,現存305篇(此外有目無詩的6篇,共311篇),分《風》、《雅》、《頌》三部分。《頌》有40篇,《雅》有105篇(《小雅》中有6篇有目無詩,不計算在內),《風》的數量最多,共160篇,合起來是305篇。古人取其整數,常說“詩三百”。
詞庫示例: 君子好逑 悠哉悠哉 左右采之 琴瑟友之 施於中谷 黃鳥于飛 

GitHub專案連結:

scel檔案:https://github.com/CQiang27/Spark_Python/tree/master/Scel

Python原始碼:https://github.com/CQiang27/Spark_Python/blob/master/scel_TR_txt.ipynb

 

參考文獻:

[1] 多個.scel合併為同一dict,並去重,https://blog.csdn.net/leitouguan8655/article/details/82834517

[2] scel2txt 搜狗scel格式轉txt python3,https://blog.csdn.net/cFarmerReally/article/details/78149648

[3] Python中struct.pack()和struct.unpack()用法詳細說明,http://www.php.cn/python-tutorials-356984.html