關(guān)于PHP的相似度計(jì)算函數(shù):levenshtein的使用介紹
使用說明
先看手冊(cè)上 levenshtein() 函數(shù)的說明:
levenshtein() 函數(shù)返回兩個(gè)字符串之間的 Levenshtein 距離。
Levenshtein 距離,又稱編輯距離,指的是兩個(gè)字符串之間,由一個(gè)轉(zhuǎn)換成另一個(gè)所需的最少編輯操作次數(shù)。許可的編輯操作包括將一個(gè)字符替換成另一個(gè)字符,一個(gè)字符,刪除一個(gè)字符。
例如把 kitten 轉(zhuǎn)換為 sitting:
sitten (k→s)
sittin (e→i)
sitting (→g)levenshtein() 函數(shù)給每個(gè)操作(替換和刪除)相同的權(quán)重。不過,您可以通過設(shè)置可選的 insert、replace、delete 參數(shù),來定義每個(gè)操作的代價(jià)。
語法:
levenshtein(string1,string2,insert,replace,delete)
參數(shù) 描述
string1 必需。要對(duì)比的第一個(gè)字符串。
string2 必需。要對(duì)比的第二個(gè)字符串。
insert 可選。一個(gè)字符的代價(jià)。默認(rèn)是 1。
replace 可選。替換一個(gè)字符的代價(jià)。默認(rèn)是 1。
delete 可選。刪除一個(gè)字符的代價(jià)。默認(rèn)是 1。
提示和注釋
如果其中一個(gè)字符串超過 255 個(gè)字符,levenshtein() 函數(shù)返回 -1。
levenshtein() 函數(shù)對(duì)大小寫不敏感。
levenshtein() 函數(shù)比 similar_text() 函數(shù)更快。不過,similar_text() 函數(shù)提供需要更少修改的更精確的結(jié)果。
例子
<?php
echo levenshtein("Hello World","ello World");
echo "<br />";
echo levenshtein("Hello World","ello World",10,20,30);
?>
輸出: 1 30
源碼分析
levenshtein() 屬于標(biāo)準(zhǔn)函數(shù),在/ext/standard/目錄下有專門針對(duì)此函數(shù)實(shí)現(xiàn)的文件:levenshtein.c。
levenshtein()會(huì)根據(jù)參數(shù)個(gè)數(shù)選擇實(shí)現(xiàn)方式,針對(duì)參數(shù)為2和參數(shù)為5的情況,都會(huì)調(diào)用 reference_levdist() 函數(shù)計(jì)算距離。其不同在于對(duì)后三個(gè)參數(shù),參數(shù)為2時(shí),使用默認(rèn)值1。
并且在實(shí)現(xiàn)源碼中我們發(fā)現(xiàn)了一個(gè)在文檔中沒有說明的情況: levenshtein() 函數(shù)還可以傳遞三個(gè)參數(shù),其最終會(huì)調(diào)用 custom_levdist() 函數(shù)。它將第三個(gè)參數(shù)作為自定義函數(shù)的實(shí)現(xiàn),其調(diào)用示例如下:
echo levenshtein("Hello World","ello World", 'strsub');
執(zhí)行會(huì)報(bào)Warning: The general Levenshtein support is not there yet。這是因?yàn)楝F(xiàn)在這個(gè)方法還沒有實(shí)現(xiàn),僅僅是放了一個(gè)坑在那。
reference_levdist() 函數(shù)的實(shí)現(xiàn)算法是一個(gè)經(jīng)典的DP問題。
給定兩個(gè)字符串x和y,求最少的修改次數(shù)將x變成y。修改的規(guī)則只能是如下三種之一:刪除、改變。
用a[i][j]表示把x的前i個(gè)字符變成y的前j個(gè)字符所需的最少操作次數(shù),則狀態(tài)轉(zhuǎn)移方程為:
當(dāng)x[i]==y[j]時(shí):a[i][j] = min(a[i-1][j-1], a[i-1][j]+1, a[i][j-1]+1);
當(dāng)x[i]!=y[j]時(shí):a[i][j] = min(a[i-1][j-1], a[i-1][j], a[i][j-1])+1;
在用狀態(tài)轉(zhuǎn)移方程前,我們需要初始化(n+1)(m+1)的矩陣d,并讓第一行和列的值從0開始增長(zhǎng)。 掃描兩字符串(nm級(jí)的),對(duì)比字符,使用狀態(tài)轉(zhuǎn)移方程,最終$a[$l1][$l2]為其結(jié)果。
簡(jiǎn)單實(shí)現(xiàn)過程如下:
<?PHP
$s1 = "abcdd";
$l1 = strlen($s1);
$s2 = "aabbd";
$l2 = strlen($s2);
for ($i = 0; $i < $l1; $i++) {
$a[0][$i + 1] = $i + 1;
}
for ($i = 0; $i < $l2; $i++) {
$a[$i + 1][0] = $i + 1;
}
for ($i = 0; $i < $l2; $i++) {
for ($j = 0; $j < $l1; $j++) {
if ($s2[$i] == $s1[$j]) {
$a[$i + 1][$j + 1] = min($a[$i][$j], $a[$i][$j + 1] + 1, $a[$i + 1][$j] + 1);
}else{
$a[$i + 1][$j + 1] = min($a[$i][$j], $a[$i][$j + 1], $a[$i + 1][$j]) + 1;
}
}
}
echo $a[$l1][$l2];
echo "n";
echo levenshtein($s1, $s2);
在PHP的實(shí)現(xiàn)中,實(shí)現(xiàn)者在注釋中很清楚的標(biāo)明:此函數(shù)僅優(yōu)化了內(nèi)存使用,而沒有考慮速度,從其實(shí)現(xiàn)算法看,時(shí)間復(fù)雜度為O(m×n)。其優(yōu)化點(diǎn)在于將上面的狀態(tài)轉(zhuǎn)移方程中的二維數(shù)組變成了兩個(gè)一組數(shù)組。簡(jiǎn)單實(shí)現(xiàn)如下:
<?PHP
$s1 = "abcjfdkslfdd";
$l1 = strlen($s1);
$s2 = "aab84093840932bd";
$l2 = strlen($s2);
$dis = 0;
for ($i = 0; $i <= $l2; $i++){
$p1[$i] = $i;
}
for ($i = 0; $i < $l1; $i++){
$p2[0] = $p1[0] + 1;
for ($j = 0; $j < $l2; $j++){
if ($s1[$i] == $s2[$j]){
$dis = min($p1[$j], $p1[$j + 1] + 1, $p2[$j] + 1);
}else{
$dis = min($p1[$j] + 1, $p1[$j + 1] + 1, $p2[$j] + 1); // 注意這里最后一個(gè)參數(shù)為$p2
}
$p2[$j + 1] = $dis;
}
$tmp = $p1;
$p1 = $p2;
$p2 = $tmp;
}
echo "n";
echo $p1[$l2];
echo "n";
echo levenshtein($s1, $s2);
如上為PHP內(nèi)核開發(fā)者對(duì)前面經(jīng)典DP的優(yōu)化,其優(yōu)化點(diǎn)在于不停的復(fù)用兩個(gè)一維數(shù)組,一個(gè)記錄上次的結(jié)果,一個(gè)記錄這一次的結(jié)果。如果按照PHP的參數(shù),分別給三個(gè)操作賦值不同的值,在上面的算法中將對(duì)應(yīng)的1變成操作對(duì)應(yīng)的值就可以了。 min函數(shù)的第一個(gè)參數(shù)對(duì)應(yīng)的是修改,第二個(gè)參數(shù)對(duì)應(yīng)的是刪除源碼天空,第三個(gè)參數(shù)對(duì)應(yīng)的是添加。
相關(guān)文章
淺談laravel 5.6 安裝 windows上使用composer的安裝過程
今天小編就為大家分享一篇淺談laravel 5.6 安裝 windows上使用composer的安裝過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-10-10
PHP中把錯(cuò)誤日志保存在系統(tǒng)日志中(Windows系統(tǒng))
這篇文章主要介紹了PHP中把錯(cuò)誤日志保存在系統(tǒng)日志中(Windows系統(tǒng)),本文講解了設(shè)置方法和查看方法,需要的朋友可以參考下2015-06-06
Laravel 5.5官方推薦的Nginx配置學(xué)習(xí)教程
這篇文章主要給大家介紹了關(guān)于Laravel 5.5官方推薦的Nginx配置學(xué)習(xí)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10
Laravel 實(shí)現(xiàn)添加多語言提示信息
今天小編就為大家分享一篇Laravel 實(shí)現(xiàn)添加多語言提示信息,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-10-10
在laravel中實(shí)現(xiàn)事務(wù)回滾的方法
今天小編就為大家分享一篇在laravel中實(shí)現(xiàn)事務(wù)回滾的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-10-10
CodeIgniter針對(duì)數(shù)據(jù)庫的連接、配置及使用方法
這篇文章主要介紹了CodeIgniter針對(duì)數(shù)據(jù)庫的連接、配置及使用方法,結(jié)合實(shí)例形式分析了CodeIgniter針對(duì)數(shù)據(jù)庫的連接配置及常用操作技巧,需要的朋友可以參考下2016-03-03
Thinkphp5框架實(shí)現(xiàn)獲取數(shù)據(jù)庫數(shù)據(jù)到視圖的方法
這篇文章主要介紹了Thinkphp5框架實(shí)現(xiàn)獲取數(shù)據(jù)庫數(shù)據(jù)到視圖的方法,涉及thinkPHP5數(shù)據(jù)庫配置、讀取、模型操作及視圖調(diào)用相關(guān)操作技巧,需要的朋友可以參考下2019-08-08

