基于规则的分词
基于规则或词典的分词方法是一种较为机械的分词方法,其基本思想如下。
- 将待分词语句中的字符串和词典逐个匹配。
- 找到匹配的字符串则切分,不匹配则减去边缘的某些字符。
- 从头再次匹配,直至匹配完毕或者没有找到词典的字符串而结束。
基于规则分词主要方法如下。
- 正向最大匹配法(Maximum Match Method,MM法)。
- 逆向最大匹配法(Reverse Maximum Match Method,RMM法)。
- 双向最大匹配法(Bi-direction Matching Method,BMM法)。
python">def precompute_max_length(dictionary):"""计算词典中最大长度词的长度:param dictionary: 词典:return: 词典中最大长度词的长度"""return max(len(word) for word in dictionary) if dictionary else 0def forward_segmentation(text, dictionary):"""正向最大匹配:param text: 文本字符串:param dictionary: 词典:return: 将文本字符串中切词后的数组"""result = []i = 0max_len = precompute_max_length(dictionary)while i < len(text):found_word = ''# 尝试最长可能的词长max_possible = min(max_len, len(text) - i)for l in range(max_possible, 0, -1):candidate = text[i:i + l]if candidate in dictionary:found_word = candidatebreakif found_word:result.append(found_word)i += len(found_word)else:# 没有找到任何词,添加单个字符作为词汇result.append(text[i])i += 1return resultdef backward_segmentation(text, dictionary):"""逆向最大匹配:param text: 文本字符串:param dictionary: 词典:return: 将文本字符串中切词后的数组"""result = []i = len(text)max_len = precompute_max_length(dictionary)while i > 0:found_word = ''# 尝试最长可能的词长,从i处往回找max_possible = min(max_len, i)for l in range(max_possible, 0, -1):candidate = text[i - l:i]if candidate in dictionary:found_word = candidatebreakif found_word:result.insert(0, found_word)i -= len(found_word)else:# 没有找到任何词,添加最后一个字符作为词汇result.insert(0, text[i - 1])i -= 1return resultdef bidirectional_segmentation(text, dictionary):"""
双向最大匹配
:param text: 文本字符串
:param dictionary: 词典
:return: 将文本字符串中切词后的数组
"""result = []i = 0n = len(text)max_len = precompute_max_length(dictionary)while i < n:# 正向扫描查找词forward_word = ''max_possible_forward = min(max_len, n - i)for l in range(max_possible_forward, 0, -1):candidate = text[i:i + l]if candidate in dictionary:forward_word = candidatebreak# 反向扫描查找词backward_word = ''max_possible_backward = min(max_len, i)for l in range(max_possible_backward, 0, -1):candidate = text[i - l:i]if candidate in dictionary:backward_word = candidatebreak# 判断选择哪个词,如果长度相同则优先正向词?if len(forward_word) >= len(backward_word):result.append(forward_word)i += len(forward_word)else:result.append(backward_word)i -= len(backward_word)return result# 定义词典
word_set = {"中", "华", "民", "共和", "国", "人民", "共和国"}# 定义文本字符串
text = "中华人民共和国"# 正向分词
forward_result = forward_segmentation(text, word_set)
print("正向分词结果:", forward_result)# 逆向分词
backward_result = backward_segmentation(text, word_set)
print("逆向分词结果:", backward_result)# 双向分词
bidirectional_result = bidirectional_segmentation(text, word_set)
print("双向分词结果:", bidirectional_result)
正向分词结果: ['中', '华', '人民', '共和国']
逆向分词结果: ['中', '华', '人民', '共和国']
双向分词结果: ['中', '华', '人民', '共和国']
以下是代码的详细注释,解释了每个函数的功能和实现逻辑:
precompute_max_length(dictionary)
计算词典中最长单词的长度。
如果词典为空,则返回0。
python">def precompute_max_length(dictionary):# 如果词典不为空,返回词典中最长单词的长度return max(len(word) for word in dictionary) if dictionary else 0
forward_segmentation(text, dictionary)
正向最大匹配分词算法。
从左到右扫描文本,每次尝试匹配最长的单词。
python">def forward_segmentation(text, dictionary):result = [] # 存储分词结果i = 0 # 当前扫描位置max_len = precompute_max_length(dictionary) # 获取词典中最长单词的长度while i < len(text): # 遍历文本found_word = '' # 用于存储找到的单词# 计算当前扫描位置的最大可能匹配长度max_possible = min(max_len, len(text) - i)for l in range(max_possible, 0, -1): # 从最大可能长度开始递减candidate = text[i:i+l] # 提取当前候选单词if candidate in dictionary: # 如果候选单词在词典中found_word = candidate # 找到匹配单词breakif found_word: # 如果找到匹配单词result.append(found_word) # 将单词加入结果i += len(found_word) # 更新扫描位置else: # 如果没有找到匹配单词result.append(text[i]) # 将当前字符作为单字加入结果i += 1 # 更新扫描位置return result # 返回分词结果
backward_segmentation(text, dictionary)
逆向最大匹配分词算法。
从右到左扫描文本,每次尝试匹配最长的单词。
python">def backward_segmentation(text, dictionary):result = [] # 存储分词结果i = len(text) # 当前扫描位置(从文本末尾开始)max_len = precompute_max_length(dictionary) # 获取词典中最长单词的长度while i > 0: # 遍历文本found_word = '' # 用于存储找到的单词# 计算当前扫描位置的最大可能匹配长度max_possible = min(max_len, i)for l in range(max_possible, 0, -1): # 从最大可能长度开始递减candidate = text[i-l:i] # 提取当前候选单词if candidate in dictionary: # 如果候选单词在词典中found_word = candidate # 找到匹配单词breakif found_word: # 如果找到匹配单词result.insert(0, found_word) # 将单词插入结果列表的开头i -= len(found_word) # 更新扫描位置else: # 如果没有找到匹配单词result.insert(0, text[i-1]) # 将当前字符作为单字插入结果列表的开头i -= 1 # 更新扫描位置return result # 返回分词结果
bidirectional_segmentation(text, dictionary)
双向最大匹配分词算法。
结合正向和逆向最大匹配算法,选择匹配长度更长的单词。
python">def bidirectional_segmentation(text, dictionary):result = [] # 存储分词结果i = 0 # 当前扫描位置n = len(text) # 文本长度max_len = precompute_max_length(dictionary) # 获取词典中最长单词的长度while i < n: # 遍历文本# 正向扫描查找词forward_word = '' # 存储正向匹配的单词max_possible_forward = min(max_len, n - i) # 计算正向扫描的最大可能匹配长度for l in range(max_possible_forward, 0, -1): # 从最大可能长度开始递减candidate = text[i:i+l] # 提取当前候选单词if candidate in dictionary: # 如果候选单词在词典中forward_word = candidate # 找到匹配单词break# 反向扫描查找词backward_word = '' # 存储逆向匹配的单词max_possible_backward = min(max_len, i) # 计算逆向扫描的最大可能匹配长度for l in range(max_possible_backward, 0, -1): # 从最大可能长度开始递减candidate = text[i-l:i] # 提取当前候选单词if candidate in dictionary: # 如果候选单词在词典中backward_word = candidate # 找到匹配单词break# 判断选择哪个词if len(forward_word) >= len(backward_word): # 如果正向匹配的单词长度大于等于逆向匹配的单词result.append(forward_word) # 选择正向匹配的单词i += len(forward_word) # 更新扫描位置else: # 否则选择逆向匹配的单词result.append(backward_word) # 选择逆向匹配的单词i -= len(backward_word) # 更新扫描位置return result # 返回分词结果
总结
-
precompute_max_length
:计算词典中最长单词的长度,用于优化分词过程中的最大匹配长度。 -
forward_segmentation
:正向最大匹配分词算法,从左到右扫描文本,优先匹配最长的单词。 -
backward_segmentation
:逆向最大匹配分词算法,从右到左扫描文本,优先匹配最长的单词。 -
bidirectional_segmentation
:双向最大匹配分词算法,结合正向和逆向匹配,选择匹配长度更长的单词,以提高分词的准确性。