如何构建简易分词器:基于给定词典实现无空格语句分词
简易连续匹配分词器实现
核心需求
给定以列表形式存储的词典d、无间隔待处理语句s,输出切分后和词典匹配的连续分词单元(token),要求切分结果符合连续覆盖的规则,不输出零散的重叠匹配碎片。
对应测试场景:
- 测试词典:
["the","snow","ball","snowball","is","cold"] - 测试语句:
"thesnowballisverycold" - 预期输出:
["the","snowball","is","cold"]
现有实现的核心问题
当前写的递归subs函数,逻辑是枚举所有可由原文字符拼接形成的子序列,最后取枚举结果和词典的交集,这个实现存在两个本质偏差:
- 匹配范围不对:枚举的是任意字符顺序的组合子序列,不是原句中连续存在的字符串,大量非连续的拼接结果根本不属于有效分词范畴
- 没有位置约束:只要词典词条的字符在原句中按顺序出现过,不管和前后的切分段有没有位置重叠,都会被纳入结果。最后跑出来的
["snow","ball","cold","is","snowball","the"]本质是把所有能在原句找到字符顺序匹配的词典词条堆在了一起,完全不是连续切分得到的token序列,自然不符合预期。
适配需求的简易实现方案
要达到预期效果,完全不需要做全量子串枚举,用最经典的最大正向匹配规则就能实现,逻辑极简、刚好覆盖当前场景:
- 预处理阶段把词典转成集合方便快速查找,同时记录词典内最长词条的长度,减少匹配时的无效遍历
- 从语句的起始位置开始,从最长可能的匹配长度往短逐次尝试,只要当前位置往后截取的连续子串能在词典中命中,就把这个词条作为一个分词单元,将指针移动到该词条的末尾位置,继续向下匹配
- 遇到无法匹配的零散片段(比如例子中的
very),直接将指针向后移动一位跳过,不纳入最终分词结果
可直接运行的示例代码:
# 初始化词典与待处理语句 dict_list = ["the","snow","ball","snowball","is","cold"] sentence = "thesnowballisverycold" # 词典预处理:转集合优化查找效率,记录最长词条长度 word_set = set(dict_list) max_word_len = max(len(word) for word in dict_list) tokens = [] pos = 0 while pos < len(sentence): matched_word = None # 从最长匹配长度开始逐次缩短尝试 for current_len in range(min(max_word_len, len(sentence) - pos), 0, -1): sub_str = sentence[pos:pos + current_len] if sub_str in word_set: matched_word = sub_str break if matched_word: tokens.append(matched_word) pos += len(matched_word) else: # 无匹配的字符直接向后跳过 pos += 1 print(tokens)
运行上述代码的输出和预期完全一致:
['the', 'snowball', 'is', 'cold']
这个实现通过最长匹配优先的规则,天然会过滤掉短的重叠匹配(比如snow、ball),优先选更长的有效词条(比如snowball),完全符合对简易分词器的需求,没有引入额外的复杂依赖。
内容的提问来源于stack exchange,提问作者Ron
相关产品推荐
相关产品推荐

