php 中的近似字符串匹配
Approximate string matching in php
假设我需要比较两个变量
$team="Benfica(U23):Vitoria Guimaraes(U23)";
和
$team2="Benfica U23:Vitoria Guimaraes U23";
为了我的目的,$team 和 $team2 应该匹配,实际上它们是同一个灯具,只是将 U23 更改为 (U23)。
然而 preg_match 不像人类那么聪明,所以如果我使用
if (preg_match("/$team/",$team2)) {
echo "they match";
}
当然,它们不匹配。我怎样才能做一个近似值 preg_match
这样 $team 和 $team2 应该被 preg_match 检查认为是相同的(非常相似)?
例如,在上面的 preg_match 中,由于 $team 中的括号 () 而导致 4 个字符错误,我可以允许这些错误通过 preg_match 吗?
可能还有其他情况,例如 $team2 可能...
$team2="U23 Benfica:Vitoria Guimaraes";
$team2="Benfica (U23):Vitoria Guimaraes U23";
$team2="Benfica U23:Vitoria Guimaraes(U23)";
等等..各种情况,这只是一个例子。所有这些都应该与 $team 匹配,我该怎么做才能在 php 中执行这个近似字符串匹配?
谢谢
编辑:我在看到关于使用 similar_text 的评论后删除了这个答案,但我在测试字符串上的实验只给出了 team1 和 team2 之间的 78%。这可能已经足够好了,但我认为替代方案可能会有用。
值得注意的是,除非你开始使用各种伪人工智能的东西,否则你永远不会得到像人类识别这样的东西。从表面上看,您 'sure' 每个单词至少拼写相同。我建议将字符串按任何非字母数字字符拆分为一个数组,然后对数组进行排序,并检查它是否与每个团队的 'master' 匹配。
它看起来像(这是未经测试的 - $pattern 可能需要更多工作)
<?php
$teamString = "Benfica (U23):Vitoria Guimaraes U23";
$masterArray = ['Benfica','Guimares','U23','Vitoria'];
$pattern = '/[^a-zA-Z\d]/';
$teamArray = preg_split( $pattern, $teamString );
sort($teamArray);
$interArray = array_unique($teamArray); //to remove duplicate U23
$finalArray = array_filter($interArray, function($k) {
return (preg_replace('/\s+/', '', $k) != ''); //to get rid of whitespace
});
//...compare $finalArray with $masterArray
当然你可以添加逻辑来解决你发现的其他问题...
你可以用levenshtein($team, $team2)
有一个数字来表示字符串有多少不同,然后定义一个阈值来决定你想要容忍多少。
if (levenshtein($team, $team2) < 3) {
echo "string are similar";
} else {
echo "string are not similar";
}
另一种方法是在多重分解数组上使用array_intersect。
删除 ()
并替换为 space。
在 space 和冒号上展开并过滤掉所有空的。
使用 array_intersect 查看有多少个相同的项目,看看是否与唯一项目的数量相匹配。
如果您愿意,这当然可以通过计数是否在一定范围内进行校准。
$team1="U23 Benfica:Vitoria Guimaraes";
$team2="Benfica (U23):Vitoria Guimaraes U23";
var_dump(match($team1, $team2));
$team1="U23 Benfica:Vitoria Guimaraes";
$team2="Benfica U23:Vitoria Guimaraes(U23)";
var_dump(match($team1, $team2));
$team1="Benfica U23:Vitoria Guimaraes(U23)";
$team2="Benfica (U23):Vitoria Guimaraes U23";
var_dump(match($team1, $team2));
function match($s1, $s2){
// remove the ( and ) and replace with space
$s1 = str_replace(["(",")"], " ", $s1);
$s2 = str_replace(["(",")"], " ", $s2);
$delimiters = [" ", ":"]; // add more delimiters if needed
// explode on $delimiters and remove empty values
$arr1 = array_filter(multiexplode($delimiters,$s1));
$arr2 = array_filter(multiexplode($delimiters,$s2));
//var_dump($arr1, $arr2);
// How many items is equal between $arr1 and $arr2
$intersect = count(array_unique(array_intersect($arr1, $arr2)));
// is the count of equal items the same as the count of items in the strings
if($intersect == count(array_unique($arr1)) && $intersect == count(array_unique($arr2))){
return true;
}else{
return false;
}
}
// From PHP manual explode
function multiexplode ($delimiters,$string) {
$ready = str_replace($delimiters, $delimiters[0], $string);
$launch = explode($delimiters[0], $ready);
return $launch;
}
Returns:
bool(true)
bool(true)
bool(true)
假设我需要比较两个变量
$team="Benfica(U23):Vitoria Guimaraes(U23)";
和
$team2="Benfica U23:Vitoria Guimaraes U23";
为了我的目的,$team 和 $team2 应该匹配,实际上它们是同一个灯具,只是将 U23 更改为 (U23)。
然而 preg_match 不像人类那么聪明,所以如果我使用
if (preg_match("/$team/",$team2)) {
echo "they match";
}
当然,它们不匹配。我怎样才能做一个近似值 preg_match 这样 $team 和 $team2 应该被 preg_match 检查认为是相同的(非常相似)? 例如,在上面的 preg_match 中,由于 $team 中的括号 () 而导致 4 个字符错误,我可以允许这些错误通过 preg_match 吗?
可能还有其他情况,例如 $team2 可能...
$team2="U23 Benfica:Vitoria Guimaraes";
$team2="Benfica (U23):Vitoria Guimaraes U23";
$team2="Benfica U23:Vitoria Guimaraes(U23)";
等等..各种情况,这只是一个例子。所有这些都应该与 $team 匹配,我该怎么做才能在 php 中执行这个近似字符串匹配?
谢谢
编辑:我在看到关于使用 similar_text 的评论后删除了这个答案,但我在测试字符串上的实验只给出了 team1 和 team2 之间的 78%。这可能已经足够好了,但我认为替代方案可能会有用。
值得注意的是,除非你开始使用各种伪人工智能的东西,否则你永远不会得到像人类识别这样的东西。从表面上看,您 'sure' 每个单词至少拼写相同。我建议将字符串按任何非字母数字字符拆分为一个数组,然后对数组进行排序,并检查它是否与每个团队的 'master' 匹配。
它看起来像(这是未经测试的 - $pattern 可能需要更多工作)
<?php
$teamString = "Benfica (U23):Vitoria Guimaraes U23";
$masterArray = ['Benfica','Guimares','U23','Vitoria'];
$pattern = '/[^a-zA-Z\d]/';
$teamArray = preg_split( $pattern, $teamString );
sort($teamArray);
$interArray = array_unique($teamArray); //to remove duplicate U23
$finalArray = array_filter($interArray, function($k) {
return (preg_replace('/\s+/', '', $k) != ''); //to get rid of whitespace
});
//...compare $finalArray with $masterArray
当然你可以添加逻辑来解决你发现的其他问题...
你可以用levenshtein($team, $team2)
有一个数字来表示字符串有多少不同,然后定义一个阈值来决定你想要容忍多少。
if (levenshtein($team, $team2) < 3) {
echo "string are similar";
} else {
echo "string are not similar";
}
另一种方法是在多重分解数组上使用array_intersect。
删除 ()
并替换为 space。
在 space 和冒号上展开并过滤掉所有空的。
使用 array_intersect 查看有多少个相同的项目,看看是否与唯一项目的数量相匹配。
如果您愿意,这当然可以通过计数是否在一定范围内进行校准。
$team1="U23 Benfica:Vitoria Guimaraes";
$team2="Benfica (U23):Vitoria Guimaraes U23";
var_dump(match($team1, $team2));
$team1="U23 Benfica:Vitoria Guimaraes";
$team2="Benfica U23:Vitoria Guimaraes(U23)";
var_dump(match($team1, $team2));
$team1="Benfica U23:Vitoria Guimaraes(U23)";
$team2="Benfica (U23):Vitoria Guimaraes U23";
var_dump(match($team1, $team2));
function match($s1, $s2){
// remove the ( and ) and replace with space
$s1 = str_replace(["(",")"], " ", $s1);
$s2 = str_replace(["(",")"], " ", $s2);
$delimiters = [" ", ":"]; // add more delimiters if needed
// explode on $delimiters and remove empty values
$arr1 = array_filter(multiexplode($delimiters,$s1));
$arr2 = array_filter(multiexplode($delimiters,$s2));
//var_dump($arr1, $arr2);
// How many items is equal between $arr1 and $arr2
$intersect = count(array_unique(array_intersect($arr1, $arr2)));
// is the count of equal items the same as the count of items in the strings
if($intersect == count(array_unique($arr1)) && $intersect == count(array_unique($arr2))){
return true;
}else{
return false;
}
}
// From PHP manual explode
function multiexplode ($delimiters,$string) {
$ready = str_replace($delimiters, $delimiters[0], $string);
$launch = explode($delimiters[0], $ready);
return $launch;
}
Returns:
bool(true)
bool(true)
bool(true)