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
相关产品推荐
相关产品推荐

