Sorting UTF-8 by arbitrary order:
<?php
mb_internal_encoding("UTF-8");
class utf_8_german
{
// everything else is sorted at the end
static $order = '0123456789AaÄäBbCcDdEeFfGgHhIiJjKkLlMm
NnOoÖöPpQqRrSsßTtUuÜüVvWwXxYyZz';
static $char2order;
static function cmp($a, $b) {
if ($a == $b) {
return 0;
}
// lazy init mapping
if (empty(self::$char2order))
{
$order = 1;
$len = mb_strlen(self::$order);
for ($order=0; $order<$len; ++$order)
{
self::$char2order[mb_substr(self::$order, $order, 1)] = $order;
}
}
$len_a = mb_strlen($a);
$len_b = mb_strlen($b);
$max=min($len_a, $len_b);
for($i=0; $i<$max; ++$i)
{
$char_a= mb_substr($a, $i, 1);
$char_b= mb_substr($b, $i, 1);
if ($char_a == $char_b) continue;
$order_a = (isset(self::$char2order[$char_a])) ? self::$char2order[$char_a] : 9999;
$order_b = (isset(self::$char2order[$char_b])) ? self::$char2order[$char_b] : 9999;
return ($order_a < $order_b) ? -1 : 1;
}
return ($len_a < $len_b) ? -1 : 1;
}
}
// usage example:
$t = array(
'Birnen', 'Birne', 'Äpfel', 'Apfel',
);
uasort($t, 'utf_8_german::cmp');
echo '$t: <pre>'.htmlspecialchars(print_r($t,true),null,'UTF-8').'</pre>';
?>
natcasesort
(PHP 4, PHP 5)
natcasesort — 大文字小文字を区別しない"自然順"アルゴリズムを用いて配列をソートする
説明
bool natcasesort
( array
&$array
)natcasesort() は、大文字小文字を区別しないバージョンの natsort() です。
この関数は、人間が行うような手法でアルファベットまたは数字の文字列の順番を キー/値の関係を保持したままソートします。 これは、"自然順(natural ordering)"と呼ばれているものです。
パラメータ
-
array -
入力の配列。
返り値
成功した場合に TRUE を、失敗した場合に FALSE を返します。
例
例1 natcasesort() の例
<?php
$array1 = $array2 = array('IMG0.png', 'img12.png', 'img10.png', 'img2.png', 'img1.png', 'IMG3.png');
sort($array1);
echo "Standard sorting\n";
print_r($array1);
natcasesort($array2);
echo "\nNatural order sorting (case-insensitive)\n";
print_r($array2);
?>
上の例の出力は以下となります。
Standard sorting
Array
(
[0] => IMG0.png
[1] => IMG3.png
[2] => img1.png
[3] => img10.png
[4] => img12.png
[5] => img2.png
)
Natural order sorting (case-insensitive)
Array
(
[0] => IMG0.png
[4] => img1.png
[3] => img2.png
[5] => IMG3.png
[2] => img10.png
[1] => img12.png
)
より詳細な情報については、Martin Poolの» Natural Order String Comparison ページを参照ください。
参考
- natsort() - "自然順"アルゴリズムで配列をソートする
- 配列ソート関数の比較
- strnatcmp() - "自然順"アルゴリズムにより文字列比較を行う
- strnatcasecmp() - "自然順"アルゴリズムにより大文字小文字を区別しない文字列比較を行う
w-dot-rosenbach-at-netskill-de
14-Dec-2010 10:45
shawn at shawnwilkerson dot com
05-May-2009 12:03
I kept getting varied results using natcasesort and sort on mixed arrays -- per the descriptions.
Sometimes simple is better:
A little snippet of code:
<?php if($responders->num_rows) {
$i=0;
while($row= $responders->fetch_assoc()) {
$user=getUserName($row['responderID']);
$r[$i]= array("sortname"=>strtolower($user),"userName"=>$user, "userID"=>$row['responderID'], "responderID"=>$row['idresponders']);
$i++;
}
sort($r);
print_r($r);
}
?>
I simply created a lower cased sort field at the front of the result set and then sort by it -- which provides the expected result and leaves the actual needed fields unchanged.
For the curious: all user information is kept completed in another database (and table) from the content database due to security reasons. The getUser functions we have written allow us to pull only what is legally allowed without exposing anything else.
This is why a left join or something wasn't used and we have to build a pseudo result array here from both databases.
claude at schlesser dot lu
07-Jan-2009 01:41
Here a function that will natural sort an array by keys with keys that contain special characters.
<?php
function natksort($array)
{
$original_keys_arr = array();
$original_values_arr = array();
$clean_keys_arr = array();
$i = 0;
foreach ($array AS $key => $value)
{
$original_keys_arr[$i] = $key;
$original_values_arr[$i] = $value;
$clean_keys_arr[$i] = strtr($key, "ÄÖÜäöüÉÈÀËëéèàç", "AOUaouEEAEeeeac");
$i++;
}
natcasesort($clean_keys_arr);
$result_arr = array();
foreach ($clean_keys_arr AS $key => $value)
{
$original_key = $original_keys_arr[$key];
$original_value = $original_values_arr[$key];
$result_arr[$original_key] = $original_value;
}
return $result_arr;
}
?>
Hope it will be useful to somebody :)
Kim
02-Dec-2008 08:45
If your array already is sorted ASC or DESC, then natcasesort, ksort and sort (I only tested those) will invert the sorting order.
This is most troublesome since its impossible to force a sorting order. I had to use array_multisort instead and lose the natrual sorting.
Natcasesort expects a single dimension array, so if your value is an array then it will report a "Array to string conversion" notice per key/value set.
php at method5 dot de
06-Nov-2003 11:56
hi all,
this is my first post at php.net first of all thank you for this huge site :)
ok i found it usefull to post this for others. in the german language we have words like ' ' its called "umlaute" and it was a problem to me to "naturally" sort an huge array correctly so i coded this small block to get me helped, if anyone has an better idea please post and let us know as i am not a real crack :)
1. change each "umlaut" () into its "nearest" equivalent
2. natcasesorting it naturally
3. re-assiging the correct sorted array with the original-words again while keeping track of the KEY...
example-array:
$aSupplier = array(3 => "MAN",2 => "Atlas",16 => "Chevrolet",17 => "Chrysler",19 => "Citroen",24 => "DAF",25 => "Daihatsu",27 => "Daewoo",28 => "Demag",30 => "Dodge",36 => "Schierling",208 => "HIAB",38 => "Hffermann",39 => "Gergen",40 => "Kubato",41 => "Faun",43 => "Kleindienst",44 => "Swing",45 => "Neuhaus",46 => "Unimog",47 => "Meiller",48 => "Pfau-Johnston",49 => "Geesink",50 => "Schrling",51 => "Demag-Witting",53 => "Helmers",54 => "Ellermann",55 => "Jacobsen",56 => "Biki",57 => "Hansa",58 => "Kramer",59 => "Schmitz",60 => "Toro",61 => "Iseki",62 => "Haller",63 => "Kuka",64 => "Brock",65 => "Ambross",66 => "Sobernheimer",67 => "Pietsch",68 => "Kpper",69 => "Weisser",71 => "Wackenhut");
foreach ( $aSupplier as $key => $value )
{
$aSupplier2[$key] = strtr($aSupplier[$key], "", "AOUaous");
}
natcasesort($aSupplier2);
foreach ( $aSupplier2 as $key => $value )
{
if ( $aSupplier2[$key] != "" )
$aSupplier3[$key] = $aSupplier[$key];
}
echo "<pre>";
print_r($aSupplier3);
echo "</pre>";
greetz
tim
vbAlexDOSMan at Yahoo dot com
12-Sep-2003 03:21
Ulli at Stemmeler dot net: I remade your function -- it's a little more compact now -- Enjoy...
function ignorecasesort(&$array) {
/*Make each element it's lowercase self plus itself*/
/*(e.g. "MyWebSite" would become "mywebsiteMyWebSite"*/
for ($i = 0; $i < sizeof($array); $array[$i] = strtolower($array[$i]).$array[$i], $i++);
/*Sort it -- only the lowercase versions will be used*/
sort($array);
/*Take each array element, cut it in half, and add the latter half to a new array*/
/*(e.g. "mywebsiteMyWebSite" would become "MyWebSite")*/
for ($i = 0; $i < sizeof($array); $i++) {
$this = $array[$i];
$array[$i] = substr($this, (strlen($this)/2), strlen($this));
}
}
dslicer at maine dot rr dot com
02-Jun-2003 08:41
Something that should probably be documented is the fact that both natsort and natcasesort maintain the key-value associations of the array. If you natsort a numerically indexed array, a for loop will not produce the sorted order; a foreach loop, however, will produce the sorted order, but the indices won't be in numeric order. If you want natsort and natcasesort to break the key-value associations, just use array_values on the sorted array, like so:
natcasesort($arr);
$arr = array_values($arr);
tmiller25 at hotmail dot com
25-Apr-2002 09:55
add this loop to the function above if you want items which have the same first characters to be listed in a way that the shorter string comes first.
--------------------
/* short before longer (e.g. 'abc' should come before 'abcd') */
for($i=count($array)-1;$i>0;$i--) {
$str_a = $array[$i ];
$str_b = $array[$i-1];
$cmp_a = strtolower(substr($str_a,0,strlen($str_a)));
$cmp_b = strtolower(substr($str_b,0,strlen($str_a)));
if ($cmp_a==$cmp_b && strlen($str_a)<strlen($str_b)) {
$array[$i]=$str_b; $array[$i-1]=$str_a; $i+=2;
}
}
--------------------
Ulli at Stemmeler dot net
05-Apr-2002 10:01
natcasesort didn't work first time I needed something like this.
Not on my local server, not on my server on the web.
I needed an array sorted ignoring upper and lower cases. In the end lower case array-members stayed at the end of the array.
I replaced it with this function:
---------
function ignorecasesort(&$array) {
$separator="|<>|";
for($i=0;$i<sizeof($array);$i++) { $array[$i]=strtolower($array[$i]).$separator.$array[$i]; }
sort($array);
for($i=0;$i<sizeof($array);$i++) { $this=$array[$i]; $this=explode($separator,$this); $array[$i]=$this[1]; }
}
---------
