1

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

我正在尝试创建一个应用程序来测试人们的 IQ 分数(我知道它们无关紧要,对任何人都没有多大用处),没什么太严肃的,只是我的一个项目,让我在作业之间忙碌。

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

4

2 回答 2

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%.

注意

  • 该函数返回一个包含两个值的数组。第一个将长度与两个输入问题的平均值进行比较,第二个仅与最短的问题进行比较。您可以修改它返回单个值。
  • 我用于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"
}

*/
于 2013-10-19T23:31:53.877 回答
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%。通过足够大的更改,您可以将任何随机字符串转换为任何其他随机字符串。

于 2013-10-19T21:53:07.133 回答