1. 程式人生 > >字串匹配之三:拼寫錯誤檢查程式

字串匹配之三:拼寫錯誤檢查程式

DNA的匹配畢竟離生活還是遠了點,既然是字串匹配,可不可以做個拼寫錯誤檢查呢?

首先要引入一個概念,編輯距離(Edit Distance)。編輯距離指的是一個字串修改到另一個字串所需要的工序。通常有三種情況:

1.插入:"ac" -----> "abc",編輯距離為1

2.刪除:"abc" ------> "ac", 編輯距離為1

3.替換:"abc" ------>"adc", 編輯距離為1

在這裡我們定義兩個字串 x 和 y 的編輯距離為:

dist = len(x) + len(y) - score(x, y)

score指的是全域性匹配返回的分數。但是scoring_matrix怎麼辦呢?我找了一些我自己可以數得出來編輯距離的字串,然後把一些可能的值一個一個去算。這裡提到的scoring_matrix的引數有三個:diag_score(字元相同), off_diag_score(兩個字元,但是不同), dash_score(一個字元,一個 '-' )。然後發現了這三個值分別是:

diag_score: 2
off_diag_score: 1
dash_score: 0
這裡注意的是,別選擇過於複雜的字串,那樣的話編輯距離很容易數錯,比如"abcdged"與"acdad",我們僅僅靠自己匹配,很難找出最佳的匹配。

在原始碼中也有一個word_list.txt,裡面存放了7萬多個單詞。這樣我們就可以從中與給定字串相差固定編輯距離的單詞了。

def check_spelling(checked_word, dist, word_list):
 
    alphabet = set('qwertyuiopasdfghjklzxcvbnm')
    scoring_matrix = scoring_matrix = build_scoring_matrix(alphabet=alphabet, diag_score=2, off_diag_score=1, dash_score=0)
    
    answer = set([])
    for word in word_list:
        edit_distance = get_edit_distance(checked_word, word, scoring_matrix)
        if edit_distance <= dist:
            answer.add(word)
    return answer
其中get_edit_distance其實就是按照前面給出的公式計算出編輯距離的函式。我稍微測試了一下,尋找編輯距離為1的相似單詞,十幾秒就可以完成(可能是我的電腦的配置較高的緣故)。但是拼寫檢查還是追求的實時性,我一旦寫錯了一個單詞,按下空格的時候,就應該有提示。十幾秒不是可以接受的。

————————番外————————

這裡測試了一下set和list的迭代效率,發現list的迭代效率高於set,而查詢一個元素是否在物件內,set的效率遠超list,而且set佔據的記憶體相對list要下

————————番外結束——————

當用戶輸入一個單詞,我們首先可以查詢單詞是否在正確拼寫的單詞集合內(查詢一個物件是否在一個集合的效率是很高的)。如果不在,就打上波浪線,然後就可以進入查詢dist為1或者2的單詞集合了。

我突然想到word早期版本的拼寫錯誤檢查,打波浪線很快,但是進行拼寫錯誤檢查的時候要等半天,是否就是採用這樣的辦法?

然後進入查詢程式之後,進行匹配之前,可以先檢查單詞的長度,如果長度相差多於給定的dist,那麼就不用進入匹配了,直接拋棄即可。效率應該又可以提高一些。

在網際網路的時代,雲端計算的效能不言而喻,而線上編輯的時候也要實時儲存,傳送一個單詞的頻寬也很窄,因此可以把計算放到雲上,這樣幾乎就是實時的。而檢查一個單詞是否在正確拼寫的集合內的操作可以讓JavaScript來做,既可以減輕伺服器的負擔,在使用者這邊,又感覺不到絲毫的卡滯。

一口氣寫完了字串匹配的三篇文章,真是神清氣爽,而文章的抄襲檢查也是呼之欲出了。因為最近要找工作,第四篇可能會稍微晚一點,敬請期待吧。