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

PHP中基于Levenshtein距离的字符串重排及名称匹配问题求助

嘿,我来帮你搞定这个名称排序和匹配的问题!你的需求核心是把银行数据里的单词按基准名称的顺序重新排列,还要处理完全匹配、模糊匹配(用Levenshtein距离),最后把多余的单词追加到结果末尾对吧?我给你写了一套完整的实现,还包含了你提到的两个测试案例,一起来看看:

解决方案思路
  • 先预处理两个字符串,清理多余空格并转成数组,避免无效空元素干扰逻辑
  • 优先处理完全匹配:把银行数据里和基准完全一致的单词放到对应基准位置,标记已使用避免重复匹配
  • 再处理模糊匹配:对基准中未匹配的位置,用Levenshtein编辑距离找到银行数据里最相似的单词,填充到对应位置(忽略大小写让匹配更准确)
  • 最后收集银行数据里未被匹配的多余单词,追加到结果末尾
  • 额外实现了匹配百分比计算,满足你提到的需求
完整代码实现
<?php
// 封装成可复用的函数,方便多次调用
function rearrangeAndMatchName($baseName, $bankName) {
    // 预处理:清理多余空格,分割为数组并过滤空元素
    $cleanBase = array_filter(explode(" ", preg_replace("#[\s]+#", " ", $baseName)));
    $cleanBank = array_filter(explode(" ", preg_replace("#[\s]+#", " ", $bankName)));

    // 初始化变量:对应基准位置的结果、已使用的银行单词索引、未匹配的多余单词
    $matchedResult = array_fill(0, count($cleanBase), null);
    $usedBankIndexes = [];
    $unmatchedWords = [];

    // 第一步:处理完全匹配
    foreach ($cleanBank as $bankIndex => $bankWord) {
        $baseIndex = array_search($bankWord, $cleanBase);
        // 仅当基准位置未被填充,且该银行单词未被使用时才匹配
        if ($baseIndex !== false && $matchedResult[$baseIndex] === null && !in_array($bankIndex, $usedBankIndexes)) {
            $matchedResult[$baseIndex] = $bankWord;
            $usedBankIndexes[] = $bankIndex;
        }
    }

    // 第二步:处理模糊匹配(Levenshtein编辑距离)
    foreach ($cleanBase as $baseIndex => $baseWord) {
        if ($matchedResult[$baseIndex] !== null) continue; // 已完全匹配的位置跳过

        $minDistance = PHP_INT_MAX;
        $bestMatchIndex = -1;

        // 遍历未使用的银行单词,找最相似的
        foreach ($cleanBank as $bankIndex => $bankWord) {
            if (in_array($bankIndex, $usedBankIndexes)) continue;

            // 忽略大小写计算编辑距离,提升匹配合理性
            $distance = levenshtein(strtolower($bankWord), strtolower($baseWord));
            if ($distance < $minDistance) {
                $minDistance = $distance;
                $bestMatchIndex = $bankIndex;
            }
        }

        // 找到相似匹配项后,填充并标记已使用
        if ($bestMatchIndex !== -1) {
            $matchedResult[$baseIndex] = $cleanBank[$bestMatchIndex];
            $usedBankIndexes[] = $bestMatchIndex;
        }
    }

    // 第三步:收集未匹配的多余单词
    foreach ($cleanBank as $bankIndex => $bankWord) {
        if (!in_array($bankIndex, $usedBankIndexes)) {
            $unmatchedWords[] = $bankWord;
        }
    }

    // 合并最终结果:匹配好的顺序 + 未匹配的多余单词
    $finalResult = array_merge(array_filter($matchedResult), $unmatchedWords);
    $finalName = implode(" ", $finalResult);

    // 计算匹配百分比
    $matchedCount = count(array_filter($matchedResult));
    $matchPercentage = ($matchedCount / count($cleanBase)) * 100;

    return [
        'final_name' => $finalName,
        'match_percentage' => number_format($matchPercentage, 2) . "%"
    ];
}

// 测试案例1:完全匹配场景
echo "<h3>案例1:完全匹配测试</h3>";
$dataBaseName1 = "Jardine Lloyd Thompson";
$bankdata1 = "Thompson Jardine Lloyd";
$result1 = rearrangeAndMatchName($dataBaseName1, $bankdata1);
echo "基准名称:{$dataBaseName1}<br>";
echo "银行名称:{$bankdata1}<br>";
echo "预期输出:Jardine Lloyd Thompson<br>";
echo "实际输出:{$result1['final_name']}<br>";
echo "匹配百分比:{$result1['match_percentage']}<br><br>";

// 测试案例2:模糊匹配场景
echo "<h3>案例2:模糊匹配测试</h3>";
$dataBaseName2 = "Jardine Lloyd Thompson";
$bankdata2 = "Thoapson Jordine Llayd";
$result2 = rearrangeAndMatchName($dataBaseName2, $bankdata2);
echo "基准名称:{$dataBaseName2}<br>";
echo "银行名称:{$bankdata2}<br>";
echo "预期输出:Jordine Llayd Thoapson<br>";
echo "实际输出:{$result2['final_name']}<br>";
echo "匹配百分比:{$result2['match_percentage']}<br>";
?>
关键逻辑说明
  • 预处理步骤:用preg_replace把多个连续空格替换为单个,再用array_filter过滤掉可能出现的空数组元素(比如字符串首尾空格导致的空项),确保后续逻辑稳定
  • 完全匹配优先级:优先处理完全一致的单词,避免模糊匹配抢占正确的对应位置
  • Levenshtein距离匹配:通过计算两个单词的编辑距离(即最少需要多少次增删改操作才能让两个单词一致),找到最相似的单词,忽略大小写让匹配更符合实际场景
  • 多余单词处理:把银行数据中未被匹配到基准位置的单词统一追加到结果末尾,保证所有单词都被保留

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:09:12