jieba源碼研讀筆記(十一) - 詞性標注之POSTokenizer初探
前言
前篇看了posseg/__init__.py
檔的大架構,這裡將繼續介紹檔案中的POSTokenizer
這個類別。
本篇僅介紹POSTokenizer
類別初始化及載入字典的部份,核心函數及其wrapper將會在後續的文章裡介紹。
POSTokenizer類別
初始化
class POSTokenizer(object):
def __init__(self, tokenizer=None):
# 它需要借用jieba.Tokenizer的get_dict_file, get_DAG, calc等函數
# 所以這裡才會定義了tokenizer這個屬性
self.tokenizer = tokenizer or jieba.Tokenizer()
# 這一句怎麼同時出現在__init__()及initialize()?
self.load_word_tag(self.tokenizer.get_dict_file())
def __repr__(self):
return '<POSTokenizer tokenizer=%r>' % self.tokenizer
def __getattr__(self, name):
if name in ('cut_for_search', 'lcut_for_search', 'tokenize'):
# may be possible?
raise NotImplementedError
# POSTokenizer並未實作cut_for_search, lcut_for_search, tokenize
# 其餘的功能如cut, lcut等有被POSTokenizer覆寫,所以可以使用
return getattr(self.tokenizer, name)
def initialize(self, dictionary=None):
self.tokenizer.initialize(dictionary)
# 這一句怎麼同時出現在__init__()及initialize()?
self.load_word_tag(self.tokenizer.get_dict_file())
載入字典
class POSTokenizer(object):
# ...
def load_word_tag(self, f):
#這個函數接受一個開啟的file object當作輸入,然後將它的內容讀到一個dict內
#從jieba/dict.txt中載入word_tag_tab
self.word_tag_tab = {} #一個把詞彙對應到詞性的字典
f_name = resolve_filename(f)
for lineno, line in enumerate(f, 1):
try:
line = line.strip().decode("utf-8")
if not line:
continue
word, _, tag = line.split(" ")
self.word_tag_tab[word] = tag
except Exception:
raise ValueError(
'invalid POS dictionary entry in %s at Line %s: %s' % (f_name, lineno, line))
f.close()
def makesure_userdict_loaded(self):
#在使用者有用add_word增加新詞時self.tokenizer.user_word_tag_tab才會不為空
if self.tokenizer.user_word_tag_tab:
#參考https://www.programiz.com/python-programming/methods/dictionary/update
#字典1.update(字典2):如果字典2的key不在字典1中,則把該key加入字典1;
#如果字典2的key己經存在字典1中,則更新字典1中該key的值
self.word_tag_tab.update(self.tokenizer.user_word_tag_tab)
self.tokenizer.user_word_tag_tab = {}
dict.txt
中的內容:
AT&T 3 nz
B超 3 n
c# 3 nz
C# 3 nz
c++ 3 nz
C++ 3 nz
T恤 4 n
A座 3 n
A股 3 n
…
可以看出字典中的三個欄位分別是詞彙本身,詞頻以及它的詞性。
load_word_tag
這個函數讀取dict.txt
,用以建立word_tag_tab
這個dict,把詞彙本身對應到詞性去。
如果使用者有自定義詞彙,那麼makesure_userdict_loaded
函數會將它們加入word_tag_tab
。
詞性標注核心函數
這裡定義的幾個函數實現了POSTokenizer
的核心功能,在後續的章節裡將會一一介紹。
class POSTokenizer(object):
# ...
def __cut(self, sentence):
...
def __cut_detail(self, sentence):
...
def __cut_DAG_NO_HMM(self, sentence):
...
def __cut_DAG(self, sentence):
...
詞性標注函數wrapper
這裡定義了詞性標注函數的wrapper,一樣留在後續的章節裡介紹。
class POSTokenizer(object):
# ...
def __cut_internal(self, sentence, HMM=True):
...
def _lcut_internal(self, sentence):
return list(self.__cut_internal(sentence))
def _lcut_internal_no_hmm(self, sentence):
return list(self.__cut_internal(sentence, False))
def cut(self, sentence, HMM=True):
for w in self.__cut_internal(sentence, HMM=HMM):
yield w
def lcut(self, *args, **kwargs):
return list(self.cut(*args, **kwargs))