1、结巴的简单使用
from __future__ import unicode_literals
import sys
sys.path.append("/opt/python_workspace/jieba_demo/jieba-master/")
import jieba
import jieba.posseg
import jieba.analyse
print('='*40)
print('1. 分词')
print('-'*40)
seg_list = jieba.cut("去北京大学打篮球", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("去北京大学打篮球", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
seg_list = jieba.cut("去北京大学打篮球")
print("/ ".join(seg_list)) # 默认精确模式
seg_list = jieba.cut_for_search("今天是2015年9月3号,去天安门广场庆祝抗战胜利70周年")
print("Search Mode: " + "/ ".join(seg_list)) # 搜索引擎模式
上面的代码运行结果如下:
Full Mode: 去/ 北京/ 北京大学/ 大学/ 打篮球/ 篮球
Default Mode: 去/ 北京大学/ 打篮球
去/ 北京大学/ 打篮球
Search Mode: 今天/ 是/ 2015/ 年/ 9/ 月/ 3/ 号/ ,/ 去/ 天安/ 广场/ 天安门/ 天安门广场/ 庆祝/ 抗战/ 胜利/ 70/ 周年
通过上面的例子再次验证了jieba分词具有三种模式:
1. 精确模式,试图将句子最精确地切开,适合文本分析;
2. 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
3. 搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词
2、结巴分词步骤源码解析
通过运行上面的例子,我们对结巴分词大致有了一个简单的认识。不难发现,我们上面的例子都是调用了cut这个方法,经过查看jieba的源码,发现cut是jieba分词的入口,这个函数在文件jieba/__init__.py ,代码如下:
#jieba分词的主函数,返回结果是一个可迭代的 generator
def cut(self, sentence, cut_all=False, HMM=True):
'''
The main function that segments an entire sentence that contains
Chinese characters into seperated words.
Parameter:
- sentence: The str(unicode) to be segmented.
- cut_all: Model type. True for full pattern, False for accurate pattern.
- HMM: Whether to use the Hidden Markov Model.
'''
# 解码为unicode
sentence = strdecode(sentence)
# 不同模式下的正则
if cut_all:
re_han = re_han_cut_all #re.compile("([\u4E00-\u9FD5]+)", re.U)
re_skip = re_skip_cut_all #re.compile("[^a-zA-Z0-9+#\n]", re.U)
else:
re_han = re_han_default #re.compile("([\u4E00-\u9FD5a-zA-Z0-9+#&\._]+)", re.U)
re_skip = re_skip_default #re.compile("(\r\n|\s)", re.U)
#设置不同模式下的cut_block分词方法
if cut_all:
cut_block = self.__cut_all #全模式
elif HMM:
cut_block = self.__cut_DAG #精确模式,使用隐马模型
else:
cut_block = self.__cut_DAG_NO_HMM #精确模式,不使用隐马模型
#先用正则对句子进行切分
blocks = re_han.split(sentence)
for blk in blocks:
if not blk:
continue
if re_han.match(blk): # re_han匹配的串
for word in cut_block(blk): #根据不同模式的方法进行分词
yield word
else: # 按照re_skip正则表对blk进行重新切分
tmp = re_skip.split(blk) # 返回list
for x in tmp:
if re_skip.match(x):
yield x
elif not cut_all: # 精准模式下逐个字符输出
for xx in x:
yield xx
else:
yield x
下面根据cut函数来绘制出相应的流程图:
从图中可以看出,sentence先利用正则表达式切分,得到的词语列表blocks(re_han正则表达式使用了捕获括号,那么匹配的字符串也会被列入到list中返回),然后对切分后的每一个re_han匹配项blk词语利用cut_block方法进行具体的分词行为。
具体的分词流程概括起来如下:
1. 给定待分词的句子, 使用正则(re_han)获取匹配的中文字符(和英文字符)切分成的短语列表;
2. 利用get_DAG(sentence)函数获得待切分句子的DAG,首先检测(check_initialized)进程是否已经加载词库,若未初始化词库则调用initialize函数进行初始化,initialize中判断有无已经缓存的前缀词典cache_file文件,若有相应的cache文件则直接使用 marshal.load 方法加载前缀词典,若无则通过gen_pfdict对指定的词库dict.txt进行计算生成前缀词典,到jieba进程的初始化工作完成后就调用get_DAG获得句子的DAG;
3. 根据cut_block指定具体的方法(__cut_all,__cut_DAG,__cut_DAG_NO_HMM)对每个短语使用DAG进行分词 ,如cut_block=__cut_DAG时则使用DAG(查字典)和动态规划, 得到最大概率路径, 对DAG中那些没有在字典中查到的字, 组合成一个新的片段短语, 使用HMM模型进行分词, 也就是作者说的识别新词, 即识别字典外的新词;
4. 使用python的yield 语法生成一个词语生成器, 逐词语返回;
具体执行流程总结为下图:
以上就是对结巴分词的cut源码进行分析和总结,下面会对结巴分词的一些重要方法进行进一步的分析和总结。