You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP按序列对比句子单词 解决array_diff重复词漏统计问题

现有方案核心缺陷

用array_diff做对比的逻辑,本质是基于「值存在性」的无状态匹配,完全不满足序列-wise对比的要求,核心问题有两个:

  • 不校验词的出现频次:只要用户输入中出现过1次某个单词,原句中所有同值的重复单词都会被判定为“已匹配”。比如原句有2个am,用户只输入1个am,漏打的那个am根本不会被统计到。举个极端例子:原句是两个连续的a,用户只打了1个a,array_diff会直接因为用户输入里存在a,把原句两个a都判定为已匹配,漏打数算成0,结果完全不准。
  • 不校验序列位置:哪怕用户把所有单词的顺序完全打乱,只要所有单词值都能在对方数组里找到,就会被判定为完全匹配,不符合逐句输入的业务场景。

拿题目中的测试用例跑原逻辑,输出的总错误数是2(漏lunch、多dinner),但实际漏打了1个am,真实错误数应该是3,结果存在明显偏差。

适配场景的实现方案

这个场景的核心是做词粒度的序列对齐计算,根本不需要依赖第三方库,用基础动态规划就能实现精确统计:

  1. 把原句、用户输入句拆成逐词数组,严格按出现顺序逐位对齐
  2. 统计三类核心指标:
    • 位置与值完全匹配的单词数(正确数)
    • 原句有、序列对齐时被跳过的单词数(漏打数)
    • 用户输入有、序列对齐时额外多出来的单词数(多打数)

可直接复用的PHP实现

function calculateWordMatchStats(array $originalWords, array $typedWords): array {
    $origLen = count($originalWords);
    $typedLen = count($typedWords);
    // 构建DP表,dp[i][j] 表示原句前i个词 对齐 用户输入前j个词的最小操作数
    $dp = [];
    for ($i = 0; $i <= $origLen; $i++) {
        $dp[$i][0] = $i; // 原句前i个词全是漏打的操作数
    }
    for ($j = 0; $j <= $typedLen; $j++) {
        $dp[0][$j] = $j; // 用户输入前j个词全是多打的操作数
    }
    // 填充DP表
    for ($i = 1; $i <= $origLen; $i++) {
        for ($j = 1; $j <= $typedLen; $j++) {
            // 两个位置的词完全一致,不需要额外操作
            if ($originalWords[$i-1] === $typedWords[$j-1]) {
                $dp[$i][$j] = $dp[$i-1][$j-1];
            } else {
                // 两种操作取最小值:漏打原句词、多打用户输入词(打错字的替换本质就是漏1个+多1个,不单独统计)
                $dp[$i][$j] = min(
                    $dp[$i-1][$j] + 1,
                    $dp[$i][$j-1] + 1
                );
            }
        }
    }
    // 回溯DP表,分类统计计数
    $correct = 0;
    $missing = 0;
    $extra = 0;
    $i = $origLen;
    $j = $typedLen;
    while ($i > 0 || $j > 0) {
        if ($i > 0 && $j > 0 && $originalWords[$i-1] === $typedWords[$j-1]) {
            $correct++;
            $i--;
            $j--;
        } elseif ($i > 0 && $dp[$i][$j] === $dp[$i-1][$j] + 1) {
            // 原句的词没被输入,算漏打
            $missing++;
            $i--;
        } else {
            // 用户输入的词是额外多打的
            $extra++;
            $j--;
        }
    }
    return [
        'correct_count' => $correct,
        'missing_count' => $missing,
        'extra_count' => $extra,
        'total_error' => $missing + $extra
    ];
}

示例验证

拿题目中的测试用例跑函数:

$Str1 = "i am suraj roy i am having my lunch";
$Str2 = "i suraj roy i am having my dinner";
$st1 = explode(" ", $Str1);
$st2 = explode(" ", $Str2);
$stats = calculateWordMatchStats($st1, $st2);
print_r($stats);

输出结果:

Array
(
    [correct_count] => 7 // 正确匹配的词:i、suraj、roy、i、am、having、my
    [missing_count] => 2  // 漏打:原句第二个am、lunch
    [extra_count] => 1   // 多打:dinner
    [total_error] => 3    // 总错误数
)

结果完全符合业务要求,不会漏掉重复词的漏打统计。

实现注意点
  • 对比前要统一大小写、去除特殊符号、统一空格分隔规则,避免因为格式问题导致误判
  • 这个实现是严格按输入顺序对齐的,完全匹配用户逐句看着原句输入的场景,不会出现跨位置乱匹配的问题

内容的提问来源于stack exchange,提问作者Koushik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 22:06:03