這裡介紹如何使用 Perl 的 String::Approx
模組進行模糊字串比對(approximate matching)。
模糊搜尋是實務上常用的搜尋方法,當使用者輸入的關鍵字有些誤差時,透過模糊搜尋還是可以找到使用者想要找的資訊,例如 color
與 colour
兩個字其實是一樣的,如果使用者輸入其中一個,使用一般性的比對就找不到另外一個,或是說使用者根本把單字拼錯,那一般的搜尋就更找不到了。
在 Perl 程式語言中,我們可以使用
String::Approx
這個 Perl 模組可以讓您進行模糊字串比對,以下是使用的範例教學。
首先安裝 String::Approx
這個 Perl 模組,在 Ubuntu Linux 中可以用 apt 安裝:
apt-get install libstring-approx-perl
接著就可以使用了,下面這個是一個簡單的 Hello, World 程式:
#!/usr/bin/perl use String::Approx qw(amatch); @list = <DATA>; $pattern = "strong"; @matches = amatch($pattern, @list); print @matches; __DATA__ steamer strait string stringed strings strong strophe stream stem stemming
這裡我們首先引入 String::Approx
模組的 amatch
函數,然後利用 amatch
比對 @list
中的字串,搜尋 $pattern
這個關鍵字,並輸出比對成功的字串結果。
__DATA__
那一行以下的都是一般的文字資料,放在這裡的資料可以在程式中使用 <DATA>
來讀取。這裡我們將 $pattern
設為 strong
,而程式執行之後,搜尋出來的結果會像這樣:
string stringed strings strong
除了找出 strong
之外,幾個類似的字眼也會一併找出來,如果使用者是要找 string
,但是打錯字輸入成 strong
,用模糊搜尋還是可以找得出來,這就是模糊搜尋的好處。
如果只是要判斷是否有比對成功,可以這樣做:
if (amatch($pattern, @list)) { # matched }
在預設的情況下,amatch
會比對兩個字串之間的差異,如果差異在一定的門檻值以內(預設為 $pattern
長度的十分之一),就會視為比對成功,差異的計算是看 $pattern
與比對的字串之間增加、減少或是改變了幾個字元,實際的計算方式請參考 Levenshtein distance 的說明。
您可以直接指定這個字串差異的門檻值,可以使用百分比,或是差異數目(edit),或是兩者同時使用:
amatch($pattern, ["3 30%"], @list);
當同時指定多個值的時候,amatch
會檢查每一個門檻值,當每一個門檻值都符合的時候,才會視為比對成功。
另外也可以針對插入(Insertions)、刪除(Deletions)與替換(Substitutions)的門檻值做指定:
amatch($pattern, ["I2 D20% S0"], @list);
加入 i
可以讓比對時忽略大小寫的差異:
amatch($pattern, ["i I2 D20% S0"], @list);
如果想要檢查 字串之間的 Levenshtein distance,可以使用 adist
:
use String::Approx 'adist'; $dist = adist("pattern", $input); @dist = adist("pattern", @input);
另外也可以使用 adistr
計算相對的距離,如果距離為 0
代表完全符合,若是 1
代表完全不符合:
use String::Approx 'adistr'; $dist = adistr("pattern", $input); @dist = adistr("pattern", @inputs);
您可以結合 adist
或 adistr
將多個字串依照相似性來排序,這個排序方法在許多應用上都常常用到:
my %d; @d{@inputs} = map { abs } adistr("pattern", @inputs); my @d = sort { $d{$a} <=> $d{$b} } @inputs;
如果您只是想要計算字串之間的 Levenshtein distance,那麼也可以使用 Perl 的 Text::Levenshtein
與 Text::LevenshteinXS
模組,另外 Text::WagnerFischer
與 Text::PhraseDistance
也可以做類似的事情。
最後要提醒一點,String::Approx
的執行速度通常比 Perl 內建的比對函數慢上數十倍,所以如果您需要比對大量的字串時,建議還是盡量使用一般的常規表達式來處理,真的沒辦法才使用 String::Approx
模組。
參考資料:Safari Books Online