PHP中的类似文本

时间:2013-07-13 06:52:44

标签: php arrays similarity

我有像这样的PHP数组

$array = array("foo", "bar", "hallo", "world", "fooo", "bar1", "hall_o", "wor1ld", "foo", "bard", "hzallo", "w44orld");

我想将数组的每个元素与剩余元素进行比较。

例如:我想要完成"foo" with "bar", "hallo", "world", "fooo", "bar1", "hall_o", "wor1ld", "foo", "bard", "hzallo" and "w44orld"

然后,我想要压缩"bar" with "foo", "hallo", "world", "fooo", "bar1", "hall_o", "wor1ld", "foo", "bard", "hzallo", "w44orld" 等等,直到最后一个元素。

让我们考虑元素,我们将其作为$var_1进行比较,将剩余元素的变量视为$ var_2; 如果similar_text($var_1, $var_2, $percent);返回$percent value > 90%,那么我想要打印 $var_1以及匹配百分比>的$var_2的所有相应类似文字值90

目前我计划使用两个循环实现此目的,$var_1的外部循环和$var_2的内部循环。 array的每个元素最多可以包含5000个字符,并且数组中可以有1000个元素,因此我当前的逻辑非常昂贵。

以更好的方式处理它的任何方向?

2 个答案:

答案 0 :(得分:3)

为了使索引工作,数组$arr必须具有唯一值:

$arr = array("foo", "bar", "hallo", "world", "fooo", "bar1", "hall_o", "wor1ld", "bard", "hzallo", "w44orld");
$dexed = array();
foreach ($arr as $key => $value){
    $dexed[$key]['val'] = $value;
    $dexed[$key]['key'] = $key;
}
$out = array();//output
$rev = array();//reverse lookup array
$t = 80;//threshold value
$cnt = count($dexed);
$k = 0;
for ($i=0; $i<$cnt-1; $i++){
    for ($j=$i+1; $j<$cnt; $j++){
        //similar_text calculates differently depending on order of arguments
        similar_text($dexed[$i]['val'], $dexed[$j]['val'], $percent1);
        similar_text($dexed[$j]['val'], $dexed[$i]['val'], $percent2);
        if (($percent1 >= $t) || ($percent2 >= $t)){
            //check if value already exists under different key
            if (in_array($dexed[$i]['val'], array_keys($rev))){
                if ( ! in_array($dexed[$j]['val'], array_keys($rev))){
                    $fkey = $rev[$dexed[$i]['val']];//key found
                    $next = count($out[$fkey]);
                    $out[$fkey][$next]['val'] = $dexed[$j]['val'];
                    $out[$fkey][$next]['key'] = $dexed[$j]['key'];
                    $rev[$dexed[$j]['val']] = $fkey;
                }
            } else {
                $out[$k][0]['val'] = $dexed[$i]['val'];
                $out[$k][0]['key'] = $dexed[$i]['key'];
                $out[$k][1]['val'] = $dexed[$j]['val'];
                $out[$k][1]['key'] = $dexed[$j]['key'];
                $rev[$dexed[$i]['val']] = $k;
                $rev[$dexed[$j]['val']] = $k;
                $k++;
            }
        }
    }
}

生成$out后,使用以下命令生成索引数组:

$index = array();
foreach ($out as $key => $group){
    $cnt = count($group);
    foreach ($group as $key2 => $word){
        for ($i=0; $i<$cnt; $i++){
            if ($i != $key2){
                $index[$word['key']][] = $key.':'.$i;
            }
        }
    }
}

访问给定键的所有相似字词(原始数组$arr中字词的键值);

$key = 2;
foreach ($index[$key] as $value){
    $parts = explode(':', $value);
    echo '<p>'.$out[$parts[0]][$parts[1]]['val'].'</p>';
}

答案 1 :(得分:2)

不幸的是,如果列表变得比琐碎的更大并且不能很好地工作,那么你所建议的是缓慢的。这可能是,而且在算法上也是有效的。

首先,创建一个字母bigrams(http://en.wikipedia.org/wiki/Bigram)的倒排索引。例如(假设不区分大小写):

  1. “foo”=&gt; ^ F,FO,OO,邻$
  2. “hzallo”=&gt; ^ h时,赫兹,ZA,人,LL,邻$
  3. 您可以使用下划线而不是^和$,它们是伪字符。我认为他们会帮助你对结果进行排名。

    现在要找到相似的单词,您可以使用典型的排名算法(请参阅tf * idf和更简单的基于令牌计数的算法)来对最佳匹配进行排名。所以,给“hallo”,

    QUERY(^ h,ha,al,ll,lo,o $)AGAINST index_of_words

    &安培;你会得到一个很好的匹配“hzallo”因为^ h,al,ll,lo,o $都匹配。

    你需要像Solr或你的数据库的TEXT索引这样做,除非你想写一个简单的倒排索引,但它是值得的。查找速度将比您的娱乐速度快几个数量级,并且结果将按接近程度进行排名。

    之后,你可以使用像levenshtein这样的东西,但在很多情况下我认为你不需要。