Преобразование массива

Tourmentor

Новичок
Ребят. а что если привести все элементы массива к нижнему регистру, потом отсортировать их asort-ом, потом всем элементам массива по ключу забрать элементы несортированного массива?

Только как проще это реализовать и вообще норм ли идея?

Кусок примера (правда чет не работает как надо):
PHP:
$two_forarray = $forarray;
foreach($forarray as $key=>$value) {
 $value[$key] = strtolower($value);
 }
 
 asort($forarray);
foreach($forarray as $key=>$value) {
 $value[$key] = $two_forarray[$key];
 }
 

Вурдалак

Продвинутый новичок
Блин, я не понял, ты ничего по поводу
PHP:
usort($array, 'strcasecmp');
не сказал. У тебя-то как раз вроде однобайтовая, скорее всего windows-1251, какие проблемы?
 

dimagolov

Новичок
Tourmentor, если кодировка утф-8, то с идеей сортировки без учета регистра или преобразования регистра пока придется отказаться. до выхода php6.

-~{}~ 28.01.10 09:30:

или сортировать в БД, которая это умеет делать, MySQL в отличии от ПХП по дефолту сортирует без учета регистра. понятно, что при правильной кодировке и collation. кстати, можно делать временную таблицу в памяти и там ее сортировать не трогая диск вообще.

http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
 

Вурдалак

Продвинутый новичок
Можно вот такой кодец попробовать:

PHP:
function utf8_ord($c)
{
    switch( strlen($c) )
    {
        case 1:
            return ord($c);
        break;

        case 2:
            return ((ord($c[0]) & 0x1F) << 6) | (ord($c[1]) & 0x3F);
        break;

        case 3:
            return ((ord($c[0]) & 0x0F) << 12) | ((ord($c[1]) & 0x3F) << 6) | (ord($c[2]) & 0x3F);
        break;

        case 4:
            return ((ord($c[0]) & 0x07) << 18) | ((ord($c[1]) & 0x3F) << 12) | ((ord($c[2]) & 0x3F) << 6) | (ord($c[3]) & 0x3F);
        break;

        default:
            return FALSE;
    }
}

function cmp($s1, $s2)
{
	$l = min($l1 = mb_strlen($s1, 'utf-8'), $l2 = mb_strlen($s2, 'utf-8'));

	$s1 = preg_split('//u', mb_strtolower($s1, 'utf-8'));
	$s2 = preg_split('//u', mb_strtolower($s2, 'utf-8'));

	for($i = 0; $i < $l; $i++)
	{
		if( $s1[$i] != $s2[$i] )
			return utf8_ord($s1[$i]) - utf8_ord($s2[$i]);
	}

	if( $l1 > $l )
	{	
		return 1;
	}
	else if( $l2 > $l )
	{
		return -1;
	}

	return 0;
}

usort($array, 'cmp');
Но там есть баг даже в сравнительно нестарых версия PHP с preg_split('//u', $s), который может Notice породить.
 

Tourmentor

Новичок
Буду знать, спасибо!

Проблему решил так:

PHP:
$two_forarray = $forarray;
foreach($forarray as $key=>$value) {
$forarray[$key] = strtolower($value);
 }
 
 asort($forarray);
foreach($forarray as $key=>$value) {
$forarray[$key] = $two_forarray[$key];
 }
 

Вурдалак

Продвинутый новичок
Плюс ещё тут не хватает нормализации.

-~{}~ 28.01.10 16:50:

Автор оригинала: Tourmentor
Проблему решил так:

PHP:
$two_forarray = $forarray;
foreach($forarray as $key=>$value) {
$forarray[$key] = strtolower($value);
 }
 
 asort($forarray);
foreach($forarray as $key=>$value) {
$forarray[$key] = $two_forarray[$key];
 }
— тогда strtolower() нельзя применять.
 

Вурдалак

Продвинутый новичок
strtolower() предназначена только для однобайтовых кодировок. Код правильно не будет работать.

-~{}~ 28.01.10 19:53:

В принципе, можно обойтись таким вариантом :)

PHP:
function cmp($s1, $s2)
{
	$s1 = mb_strtolower($s1, 'utf-8');
	$s2 = mb_strtolower($s2, 'utf-8');

	if( $s1 < $s2 )
	{
		return -1;
	}
	else if( $s1 > $s2 )
	{
		return 1;
	}

	return 0;
}

usort($array, 'cmp');

print_r($array);
 
Сверху