Php 运算符在答案错别字时评估为 TRUE

Php operator that evaluates TRUE on a answer typo

我正忙着为一些初等教育的学生建立ELO。

ELO 中的一些问题是 'open',因此学生应在文本框中输入答案。

假设有一道题的正确答案是"scanner"。一名学生打错字并输入 "scaner"。我不想将此答案标记为不正确。

所以我想知道 PHP 中是否有一个运算符 'resembles',与 MariaDb Sql 中的 LIKE 或数学中的双 'tilde' 相同。

我很确定我的 'problem' 有解决方法,但我只是渴望学习。

看看这个:

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

Levenshtein 算法非常适合这种情况。它适用于拼写错误或 brain-fart 时刻,例如键入 "blew" 而不是 "blue"、名称等

Levenshtein 将 return 一个数字。此数字表示两个单词之间的 "distance"。在你的场景中,我会做的是用一个小数字来确定最大距离,比如 2 或 3。这样,如果只需要一个字符更正,就可以了。但是,如果单词是 "Scanner",并且他们输入 "Skammer",它实际上不会将其作为有效响应传递。

这里有几个例子:

<?php

$threshold = 2;

$words = array('Scanner', 'Scaner', 'Skanner', 'Skammer', 'Clammer',     'Skaner');
$match = "Scanner";

foreach($words as $word){
    echo levenshtein($match, $word) . "<br>";
}

以上将输出如下:

0
1
1
3
4
2

所以你可以看到密切相关的词和 not-so 密切相关的词之间的相关性。所以,有了上面的阈值,如果我们稍微改变一下代码,我们就可以做这样的事情:

<?php

$threshold = 2;

$words = array('Scanner', 'Scaner', 'Skanner', 'Skammer', 'Clammer', 'Skaner');
$match = "Scanner";

foreach($words as $word){
    if(levenshtein($match, $word) <= $threshold) echo "$word is close enough to $match! <br>";
        else echo "$word is NOT close enough to $match! <br>";
}

我们会收到这样的回复:

Scanner is close enough to Scanner! 
Scaner is close enough to Scanner! 
Skanner is close enough to Scanner! 
Skammer is NOT close enough to Scanner! 
Clammer is NOT close enough to Scanner! 
Skaner is close enough to Scanner! 

注意 "Clammer" 与 "Scanner" 的距离是 4。让我解释一下。该距离是为了使单词匹配而必须更改的字符数。所以,"C" 必须改变,"L" 必须改变,"M" 必须改变。因此,得分为 4.

使用时请注意"S"和"s"是两个完全不同的字符,所以绝对区分大小写。我将其设置为 case-insensitive 以绝对确保 "ScAnNeR" 之类的内容不会被标记为错误答案。像这样:

<?php

$threshold = 2;

$words = array('ScAnNeR', 'Scaner', 'Skanner', 'Skammer', 'Clammer', 'Skaner');
$match = "Scanner";

foreach($words as $word){
    if(levenshtein(strtolower($match), strtolower($word)) <= $threshold) echo "$word is close enough to $match! <br>";
        else echo "$word is NOT close enough to $match! <br>";
}

注意事项

高度建议不要依赖soundex()。看看这个例子:

<?php

$threshold = 2;

$words = array('spectacular', 'spectacle');
$match = "spectacle";

foreach($words as $word){
    if(levenshtein(strtolower($match), strtolower($word)) <= $threshold) echo "$word is close enough to $match! <br>";
        else echo "$word is NOT close enough to $match! <br>";

    echo soundex($word) . "/" . soundex($match) . "<br>";
}

那个例子给出了这个结果:

spectacular is NOT close enough to spectacle! 
S123/S123
spectacle is close enough to spectacle! 
S123/S123

两个完全不同的词,甚至听起来都不一样,但根据 soundex(),它们会是绝配!虽然我认为它对某些应用程序来说是一个有用的功能,但对于这类应用程序来说,它并不是一个足够好的解决方案。在这里,另一个例子:

<?php

$threshold = 2;

$words = array('clancy', 'klancy');
$match = "clancy";

foreach($words as $word){
if(levenshtein(strtolower($match), strtolower($word)) <= $threshold) echo "$word is close enough to $match! <br>";
        else echo "$word is NOT close enough to $match! <br>";

    echo soundex($word) . "/" . soundex($match) . "<br>";
}

输出:

clancy is close enough to clancy! 
C452/C452
klancy is close enough to clancy! 
K452/C452

底线:不要依赖 soundex() 这种应用程序。您最终只会与之抗争并在此过程中被烧毁。

您可以使用 PHP 的原生功能 similar_text()。可以在这里找到信息:

http://php.net/manual/en/function.similar-text.php

有趣的是,您通过引用为最后一个参数传递了一个变量。所以你会做这样的事情:

similar_text($first, $second, $percent)

并且您可以指定 $percent 接受阈值。所以如果它们与X%相似,你可以标记它是正确的。

因为这是一个测试,我个人要求拼写正确,没有拼写错误,但是有两种可能,soundex() and similar_text():

var_dump(
    soundex('scanner') == soundex('scaner')
);

产量 true

var_dump(
    strlen('scanner') - similar_text('scanner', 'scaner')
);

产量 1 因此您需要决定可以接受多少差异。

另一种更复杂的可能性是 levenshtein(),尽管根据非常不同的假定正确答案来决定适当的距离将是一项任务。