2012-08-16 192 views
7

我想在PHP中对字符串进行排序,匹配应该首先在子字符串的第一个字母上完成,然后在整个字符串的字母上完成。对字符串进行排序,第一个字母第一个,然后是字母内部的字母

例如,如果有人搜索do,并且该列表包含

Adolf 
Doe 
Done 

结果应该是

Doe 
Done 
Adolf 

使用这样的常规sort($array, SORT_STRING)或东西不起作用,阿道夫之前排序其他。

有人有一个想法如何做到这一点?

+1

你不能这样做它用一个简单的搜索。我建议你创建多个列表,对于你正在查找的事件的每个位置,然后对这些子列表进行排序。 – Tchoupi 2012-08-16 12:37:28

+0

@ user1603166,你的问题有点含糊。从@罗曼的例子来看,如果列表中还包括“里程表”和“腹部”,应该如何排序? – Matthew 2012-08-16 13:39:13

回答

0

您可以根据stripos($str, $search)订购字符串,以便前面的字符串(stripos() == 0)首先出现。

以下代码将搜索字符串的子串位置推入单独的数组,然后使用array_multisort()将适当的排序应用于匹配;这样做而不是usort()避免了多次拨打stripos()

$k = array_map(function($v) use ($search) { 
    return stripos($v, $search); 
}, $matches); 

// $k contains all the substring positions of the search string for all matches 

array_multisort($k, SORT_NUMERIC, $matches, SORT_STRING); 

// $matches is now sorted against the position 
+0

这是一个聪明的解决方案,但如果列表中包含不包含“$ search”的字符串,它将失败。 stripos()将返回false,这等于0.(如果数组映射返回一个巨大的数字而不是false,则很容易纠正。) – Matthew 2012-08-16 13:06:07

+0

@Matthew我假设匹配已经使用grep或sth :) – 2012-08-16 13:08:38

+0

当然,理想情况下这应该与位置确定相同的步骤完成; - 让我考虑一下。 – 2012-08-16 13:29:34

3

usort(array, callback)让你根据回调进行排序。

例如(这样的事情,没有尝试)

usort($list, function($a, $b) { 
    $posa = strpos(tolower($a), 'do'); 
    $posb = strpos(tolower($b), 'do'); 
    if($posa != 0 && $posb != 0)return strcmp($a, $b); 
    if($posa == 0 && $posb == 0)return strcmp($a, $b); 
    if($posa == 0 && $posb != 0)return -1; 
    if($posa != 0 && $posb == 0)return 1; 
}); 
+0

我不明白你的答案。好的,我们让我自己分类一个函数,但问题是在这种情况下排序函数在Doe之前给了我Adolf。 – user1603166 2012-08-16 12:49:54

+0

好的,我会尽力而为,谢谢! – user1603166 2012-08-16 12:53:44

+0

取决于'usort()'内部进行了多少次比较,这可能会变得非常沉重:) – 2012-08-16 12:54:24

3

我会使用自定义排序:

<?php 
$list = ['Adolf', 'Doe', 'Done']; 

function searchFunc($needle) 
{ 
    return function ($a, $b) use ($needle) 
    { 
    $a_pos = stripos($a, $needle); 
    $b_pos = stripos($b, $needle); 

    # if needle is found in only one of the two strings, sort by that one 
    if ($a_pos === false && $b_pos !== false) return 1; 
    if ($a_pos !== false && $b_pos === false) return -1; 

    # if the positions differ, sort by the first one 
    $diff = $a_pos - $b_pos; 
    # alternatively: $diff = ($b_pos === 0) - ($a_pos === 0) 
    if ($diff) return $diff; 

    # else sort by natural case 
    return strcasecmp($a, $b); 

    }; 
} 

usort($list, searchFunc('do')); 

var_dump($list); 

输出:

array(3) { 
    [0] => 
    string(3) "Doe" 
    [1] => 
    string(4) "Done" 
    [2] => 
    string(5) "Adolf" 
} 
+1

+1。虽然OP应该知道,这里'里程表'将在'腹部'之前列出,这可能或不可取。 – Roman 2012-08-16 13:05:02

+0

@罗曼,我认为这是搜索的重点。但是,如果不是,删除'$ diff'检查和'return'将删除该行为。 – Matthew 2012-08-16 13:06:59

+0

不知道,我认为它被某种“自动完成”功能所使用,在这种情况下,我宁愿让所有'不以$字母开头'的结果按字母排序。 – Roman 2012-08-16 13:11:05

相关问题