适用于分词的前向/后向最大匹配算法

字符串最大匹配算法是建立在词典表基础上的,用于字符串分词的经典算法。根据字符串扫描的方向,可分为从前往后的前向最大匹配算法、从后往前的后向最大匹配算法,以及两者均做然后采取某些策略进行取舍的双向最大匹配算法。

字符串最大匹配算法采用了典型的贪心思想,在字符串扫描过程中,沿着既定方向不断增加长度的扫描,并与词典表上对照以找到最长的匹配子串作为当前的分词结果。但若不设置阈值,每轮扫描都会继续到字符串末尾/开头,其效率会非常低。所以,在实际操作中,一种可行的方法是设置一个滑动窗口长,限定每一轮的扫描只在该窗口范围内。

下面基于递归算法,分别提供了前向/后向最大匹配算法的实现代码:

  • 前向最大匹配算法
"""
segments: 每轮迭代,已经划分好的部分分词结果
match_word: 每轮的滑窗内匹配的最大子串,即该轮的分词结果
remaining_words:剩余的未分词的子字符串
"""
def max_forward_segment(segments, string, max_len=5):
    if len(string) == 0:
        return segments
    else:
        for i in range(max_len+1)[::-1]:
            if string[:i] in vob_list:
                match_word = string[:i]
                remaining_words = string[i:]
                break
        else:
            match_word = string[0]
            remaining_words = string[1:]
        return max_forward_segment(segments + (match_word, ) , remaining_words)
  • 后向最大匹配算法
"""
segments: 每轮迭代,已经划分好的部分分词结果
match_word: 每轮的滑窗内匹配的最大子串,即该轮的分词结果
remaining_words:剩余的未分词的子字符串
"""
def max_backward_segment(segments, string, max_len=5):
    if len(string) == 0:
        return segments
    else:
        for i in range(max_len+1)[::-1]:
            if string[-i:] in vob_list:
                match_word = string[-i:]
                remaining_words = string[:-i]
                break
        else:
            match_word = string[-1]
            remaining_words = string[:-1]
        return max_backward_segment((match_word, ) + segments, remaining_words)
  • 输出所有路径的前向匹配算法
def forward_segment(string, max_len=5):
    if len(string) == 0:
        yield ()

    else:
        counts = 0
        for i in range(1, min(len(string), max_len)+1)[::-1]:
            if string[:i] in vob_list:
                counts += 1
                match_word = string[:i]
                remaining_words = string[i:]
                for p in forward_segment(remaining_words):
                    yield (match_word,) + p

        if counts == 0:
            match_word = string[0]
            remaining_words = string[1:]
            for p in forward_segment(remaining_words):
                yield (match_word,) + p

  • 实例
vob_list = ['今天', '天天', '天气', '不错', '我', '要', '我要', '出去', '阳光', '明媚']

print(max_forward_segment((), '今天阳光明媚,我要出去玩!'))
print(max_backward_segment((), '今天阳光明媚,我要出去玩!'))
# ('今天', '阳光', '明媚', ',', '我要', '出去', '玩', '!')

print(list(forward_segment('今天天气不错,我要出去玩!')))
# [('今天', '天气', '不错', ',', '我要', '出去', '玩', '!'), ('今天', '天气', '不错', ',', '我', '要', '出去', '玩', '!')]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章