在文本中找到相似之处,更具体地说是文本的答案? - PHP

时间:2013-10-19 21:36:54

标签: php pattern-matching

我有一个独特的情况,我所要求的是为了我自己的方便,而不是我的应用程序的最终用户。

我正在尝试创建一个测试人们智商分数的应用程序(我知道它们是无关紧要的,对任何人都没有多大用处),没有太严重,只是我的一个项目让我忙于分配。

我用WAMP在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的新手,这听起来可行吗?

2 个答案:

答案 0 :(得分:1)

尝试使用Levenstein距离算法:

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%按照上面的计算。通过足够大的更改,您可以将任意随机字符串转换为任何其他随机字符串。

答案 1 :(得分: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. 上爆炸过滤后的字符串
  5. 我们过滤创建的数组
    • 删除空白 array_filter
    • 删除重复项array_unique
  6. 对第二个问题重复2-4
  7. 在两个数组中查找匹配的单词并移至新数组$intersect
  8. 计算三个数组$p1$p2$in
  9. 中每个数据的单词数
  10. 计算百分比相似度并返回
  11. 然后,您需要设置一个阈值,以确定在被视为相同之前问题的相似程度。 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"
    }
    
    */