適用於分詞的前向/後向最大匹配算法

字符串最大匹配算法是建立在詞典表基礎上的,用於字符串分詞的經典算法。根據字符串掃描的方向,可分爲從前往後的前向最大匹配算法、從後往前的後向最大匹配算法,以及兩者均做然後採取某些策略進行取捨的雙向最大匹配算法。

字符串最大匹配算法採用了典型的貪心思想,在字符串掃描過程中,沿着既定方向不斷增加長度的掃描,並與詞典表上對照以找到最長的匹配子串作爲當前的分詞結果。但若不設置閾值,每輪掃描都會繼續到字符串末尾/開頭,其效率會非常低。所以,在實際操作中,一種可行的方法是設置一個滑動窗口長,限定每一輪的掃描只在該窗口範圍內。

下面基於遞歸算法,分別提供了前向/後向最大匹配算法的實現代碼:

  • 前向最大匹配算法
"""
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('今天天氣不錯,我要出去玩!')))
# [('今天', '天氣', '不錯', ',', '我要', '出去', '玩', '!'), ('今天', '天氣', '不錯', ',', '我', '要', '出去', '玩', '!')]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章