如何用PHP编写函数返回与查询字符串最相似的列表元素
解决PHP中字符串相似度匹配的问题
你遇到的问题是因为单纯使用similar_text()或levenshtein()这类字符级算法,无法识别「候选字符串包含完整查询关键词」的场景——这两个算法的核心逻辑分别是统计相似字符数、计算编辑距离,在你的例子里:
levenshtein()会认为"Belem"更接近,因为它转成"Belem Tower"只需要添加6个字符,编辑距离远小于第二个字符串需要删除17个字符的成本;similar_text()如果只看返回的相似字符数,虽然第二个字符串的相似字符更多,但如果代码没结合百分比或权重逻辑,也可能误判。
要得到预期结果,需要结合子串匹配优先级或单词级相似度算法,以下是两种可行的实现方案:
方案一:子串匹配优先 + 字符相似度加权
先判断候选字符串是否包含完整查询(赋予高分优先级),再结合字符相似度计算最终得分,选出最高分的匹配项:
function findMostSimilar(string $query, array $candidates): string { $queryLower = strtolower($query); $bestMatch = $candidates[0]; $highestScore = -1; foreach ($candidates as $candidate) { $candidateLower = strtolower($candidate); $score = 0; // 包含完整查询直接加高分,确保优先级 if (str_contains($candidateLower, $queryLower)) { $score += 100; } // 叠加字符相似度百分比 similar_text($queryLower, $candidateLower, $percent); $score += $percent; // 更新最佳匹配 if ($score > $highestScore) { $highestScore = $score; $bestMatch = $candidate; } } return $bestMatch; } // 测试调用 $query = "Belem Tower"; $candidates = ["Belem", "Belem Tower, Lisbon, Portugal"]; echo findMostSimilar($query, $candidates); // 输出:Belem Tower, Lisbon, Portugal
方案二:基于单词的Jaccard相似度
通过拆分字符串为单词集合,计算交集与并集的比例(Jaccard相似度),同时叠加子串匹配的权重,更符合语义层面的相似判断:
// 计算两个字符串的Jaccard相似度 function calculateJaccard(string $str1, string $str2): float { $words1 = array_unique(explode(' ', strtolower($str1))); $words2 = array_unique(explode(' ', strtolower($str2))); $intersection = array_intersect($words1, $words2); $union = array_unique(array_merge($words1, $words2)); return count($union) === 0 ? 0 : count($intersection) / count($union); } function findMostSimilar(string $query, array $candidates): string { $bestMatch = $candidates[0]; $highestScore = 0; $queryLower = strtolower($query); foreach ($candidates as $candidate) { $score = calculateJaccard($query, $candidate); // 包含完整查询额外加分 if (str_contains(strtolower($candidate), $queryLower)) { $score += 0.5; } if ($score > $highestScore) { $highestScore = $score; $bestMatch = $candidate; } } return $bestMatch; }
这两种方案都能优先识别包含完整查询的字符串,解决你之前的匹配偏差问题。
内容的提问来源于stack exchange,提问作者user896541
相关产品推荐
相关产品推荐

