2013-10-19 22 views
1

我有一個獨特的情況,我所要求的是爲了我自己的方便,而不是我的應用程序的最終用戶。查找文本中的相似性,更具體地說是對文本的回答? - PHP

我試圖創建一個測試人們智商分數的應用程序(我知道它們是無關緊要的,對任何人都沒有多大用處),沒什麼太嚴肅的,只是我的一個項目讓我忙於分配任務。

我用PHP在WAMP本地編寫它。我發現在互聯網上有很多可用的IQ問題和答案,可以用於我的項目。我也注意到,有很多相同的問題,但他們的措辭略有不同。

是否有任何第三方PHP庫可用於阻止我在我的應用程序中包含「兩個」相同的問題?

一些「相同」但編程性問題的例子被認爲是不同的;

The average of 20 numbers is zero. Of them, at the most, how many may be greater than zero? 

The average of 20 numbers is zero. Of them how many may be greater than zero? 

The average of 20 numbers is zero. Of them how many may be greater than zero, at the most? 

很明顯,你可以看到,PHP本身使用運營商不能做到這一點,我試圖在問題的相似性來區分是遠遠超過我的編程技巧更大。

我查看了剽竊軟件,但沒有找到任何開源PHP項目。

有沒有更簡單的解決方案?

感謝

**編輯**

我有一個想法是將一個問題用explode在每一個空間,然後將所得數組中匹配它也有同樣的其他問題之前,功能已應用。問題越多,匹配越多?

我是PHP的新手,這聽起來可行嗎?

回答

1

作爲acfrancis已經回答:它不比使用內置的levenshtein函數更簡單。

但是,要回答您的最終問題:是的,按照您建議的方式進行操作並不困難。

代碼

function checkQuestions($para1, $para2){ 
    $arr1 = array_unique(array_filter(explode(' ', preg_replace('/[^a-zA-Z0-9]/', ' ', strtolower($para1))))); 
    $arr2 = array_unique(array_filter(explode(' ', preg_replace('/[^a-zA-Z0-9]/', ' ', strtolower($para2))))); 

    $intersect = array_intersect($arr1, $arr2); 


    $p1  = count($arr1);   //Number of words in para1 
    $p2  = count($arr2);   //Number of words in para2 
    $in  = count($intersect);  //Number of words in intersect 
    $lowest = ($p1 < $p2) ? $p1 : $p2; //Which is smaller p1 or p2? 


    return array(
     'Average' => number_format((100/(($p1+$p2)/2)) * $in, 2), //Percentage the same compared to average length of questions 
     'Smallest' => number_format((100/$lowest) * $in, 2)   //Percentage the same compared to shortest question 
     ); 
} 

說明

  1. 我們定義其接受兩個參數(參數是,我們要比較的問題)的功能。
  2. 我們過濾輸入和轉換爲數組
    • 使輸入小寫strtolower
    • 過濾掉非字母數字字符preg_replace
  3. 我們爆炸上空間中的過濾字符串
  4. 我們過濾創建的陣列
    • 刪除空白array_filter
    • 刪除重複array_unique
  5. 重複2-4第二個問題
  6. 找到匹配在兩個陣列的話,並移動到新的數組字$intersect
  7. 計數數在三個陣列$p1的,$p2$in
  8. 計算百分比相似度並返回

然後,您需要設置一個閾值,以確定問題在被視爲相同之前的相似程度。 80%

N.B.

  • 該函數返回兩個值的數組。第一個比較長度和兩個輸入問題的平均值僅次於最短。你可以修改它返回一個單一的值。
  • 我用number_format的百分比...但你會被罰款與返回的int可能

例子

例1

$question1 = 'The average of 20 numbers is zero. Of them, at the most, how many may be greater than zero?'; 
$question2 = 'The average of 20 numbers is zero. Of them how many may be greater than zero?'; 

if(checkQuestions($question1, $question2)['Average'] >= 80){ 
    echo "Questions are the same..."; 
} 
else{ 
    echo "Questions are not the same..."; 
} 

//Output: Questions are the same... 

例2

$para1 = 'The average of 20 numbers is zero. Of them, at the most, how many may be greater than zero?'; 
$para2 = 'The average of 20 numbers is zero. Of them how many may be greater than zero?'; 
$para3 = 'The average of 20 numbers is zero. Of them how many may be greater than zero, at the most?'; 

var_dump(checkQuestions($para1, $para2)); 
var_dump(checkQuestions($para1, $para3)); 
var_dump(checkQuestions($para2, $para3)); 

/** 

Output: 

array(2) { 
    ["Average"]=> 
    string(5) "93.33" 
    ["Smallest"]=> 
    string(6) "100.00" 
} 
array(2) { 
    ["Average"]=> 
    string(6) "100.00" 
    ["Smallest"]=> 
    string(6) "100.00" 
} 
array(2) { 
    ["Average"]=> 
    string(5) "93.33" 
    ["Smallest"]=> 
    string(6) "100.00" 
} 

*/ 
1

嘗試使用編輯距離算法:

http://php.net/manual/en/function.levenshtein.php

我用它(在C#,PHP沒有),一個類似的問題,那很好。我發現的技巧是將Levenstein距離除以第一句的長度(以字符爲單位)。這會給你一個將問題1轉換成問題2所需的大致百分比變化(例如)。根據我的經驗,如果你得到的東西少於50-60%(即小於0.5或0.6),那麼句子是一樣的。它可能看起來很高但注意到100%不是最大值。例如,要將字符串"z"轉換爲"abcdefghi",需要大約10個字符更改(即Levenstein距離:刪除z,然後添加abcdefghi),或者根據上面的計算更改1,000%。在足夠大的變化下,您可以將任意隨機字符串轉換爲任何其他隨機字符串。

+0

謝謝!這個,我現在就試試。 – PEPLOVE

相關問題