在字符串数组中搜索模糊字符串匹配


search through array of strings for fuzzy string match

我有两个数组,看起来如下:

$arr1 = ("stringType1AndSomeRandomStuff",
         "stringType2AndSomeRandomStuff",
         "stringType3AndSomeRandomStuff",
         "stringType1AndSomeRandomStuff",
         "stringType2AndSomeRandomStuff",
         "i don't belong here at all!",
         "stringType4AndSomeRandomStuff");

在第一个数组($arr1)中,大多数键都具有某种公共属性。在上面的示例文本中,这将是stringTypeX。这个"公共因子"是我需要搜索的。每个字符串也有一些额外的数据,例如AndSomeRandomStuff

第二个数组如下:

$arr2 = ("stringType1" => "category1",
         "stringType2" => "category2",
         "stringType3" => "category3",
         "stringType4" => "category4");

我需要遍历$arr1中的每个字符串,看看它是否与$arr2中的任何紧密匹配。如果它与其中一个键匹配,我需要$arr2

如何迭代$arr1中的每个字符串,并确定$arr2中的中的哪一个(如果有)适用?基本上,我需要遍历$arr1中的每个字符串,并对$arr2中的所有键执行部分匹配,以找到最接近的匹配。想到的直接解决方案是使用两个循环(外层用于$arr1中的所有内容,内层用于$arr2中的每个内容),但PHP中是否有一个函数可以获取字符串,并查看它是否与现有数组中的任何字符串匹配?有人知道有什么更具表演性的方法吗?

$arr1映射到一个函数,该函数计算到$arr2中键的字符串编辑距离,然后返回最接近的匹配项。看看这个Levenstein距离函数。或者,您可以简单地在映射函数中进行startsWith比较。

你可能会有这样的东西:

$stringEditDistanceThreshold = 5; // greater than this means rejected
// define the mapping function
function findClosestMatchingString($s) {
    $closestDistanceThusFar = $stringEditDistanceThreshold + 1;
    $closestMatchValue      = null;
    foreach ($arr2 as $key => $value) {
        $editDistance = levenshtein($key, $s);
        // exact match
        if ($editDistance == 0) {
            return $value;
        // best match thus far, update values to compare against/return
        } elseif ($editDistance < $closestDistanceThusFar) {
            $closestDistanceThusFar = $editDistance;
            $closestMatchValue      = $value;
        }
    }
    return $closestMatch; // possible to return null if threshold hasn't been met
}
// do the mapping
$matchingValues = array_map('findClosestMatchingString', $arr1);

您可能需要调整$stringEditDistanceThreshold,直到您获得满意的值。或者您可以使用startsWith函数,这将大大简化findClosestMatchingString的操作

最后,这不是很有效。它实际上是一个丑陋的嵌套循环。你可能可以做一些修剪或其他聪明的事情,但我怀疑如果数组相当小,你可能不会在意。

编辑:正如@Ohgodh为什么在下面的评论中所说,preg_grep可能会对你更好。在这种情况下,您的地图功能将如下所示:

function findFirstMatchingString($s) {
    $matchingKeys = preg_grep($s, array_keys($arr2));
    if (!empty($matchingKeys) {
        // return the value of the first match
        return $arr2[$matches[0]];
    }
    return null;
}