Unicode desteği PHP ile doğal bir sıralama algoritması?

3 Cevap php

Doğal bir düzen algoritması kullanarak PHP Unicode / UTF-8 karakterleri ile bir dizi sıralamak mümkün mü? (Örneğin bu dizide emir doğru sıralanır):

$array = array
(
    0 => 'Agile',
    1 => 'Ágile',
    2 => 'Àgile',
    3 => 'Âgile',
    4 => 'Ägile',
    5 => 'Ãgile',
    6 => 'Test',
);

Ben asort ($ array) ile çalışırsanız ben şu sonucu alırsınız:

Array
(
    [0] => Agile
    [6] => Test
    [2] => Àgile
    [1] => Ágile
    [3] => Âgile
    [5] => Ãgile
    [4] => Ägile
)

Ve natsort ($ array) kullanarak:

Array
(
    [2] => Àgile
    [1] => Ágile
    [3] => Âgile
    [5] => Ãgile
    [4] => Ägile
    [0] => Agile
    [6] => Test
)

Nasıl PHP 5 altında doğru sonuç sırasını (0, 1, 2, 3, 4, 5, 6) döndüren bir işlevi uygulayabilirsiniz? Tüm çoklu bayt dize fonksiyonları (mbstring, iconv, ...) benim sistemde mevcuttur.

EDIT: I want to natsort() the values, not the keys - the only reason why I'm explicitly defining the keys (and using asort() instead of sort()) is to ease the job of finding out where the sorting of unicode values yanlış gitti.

3 Cevap

Nailed it!

$array = array('Ägile', 'Ãgile', 'Test', 'カタカナ', 'かたかな', 'Ágile', 'Àgile', 'Âgile', 'Agile');

function Sortify($string)
{
    return preg_replace('~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|tilde|uml);~i', '$1' . chr(255) . '$2', htmlentities($string, ENT_QUOTES, 'UTF-8'));
}

array_multisort(array_map('Sortify', $array), $array);

Output:

Array
(
    [0] => Agile
    [1] => Ágile
    [2] => Âgile
    [3] => Àgile
    [4] => Ãgile
    [5] => Ägile
    [6] => Test
    [7] => かたかな
    [8] => カタカナ
)

Even better:

if (extension_loaded('intl') === true)
{
    collator_asort(collator_create('root'), $array);
}

@ Tchrist için teşekkürler!

Soru, ilk bakışta göründüğü gibi cevap kadar kolay değildir. Bu unicode destekler PHP'nin eksikliği tam gücü ile vurur alanlarından biridir.

Frist tüm natsort() diğer posterler tarafından önerildiği gibi sıralamak istediğiniz türü sıralama diziler ile ilgisi yoktur. Ne arıyorsanız genişletilmiş karakterleri ile dizeleri sıralama her zaman kullanılan dil bir soru olarak bir yerel farkında sıralama mekanizmasıdır. Kullanıcı örneğin Almanca atalım: Onlar aynı mektubu (DIN 5007/1) sanki A ve Ä bazen sıralanabilir, ve aslında "AE" (DIN 5007/2) olduğu gibi bazen Ä sıralanabilir. İsveççe olarak, aksine, alfabenin sonunda gelir.

Windows kullanmak istemiyorsanız PHP tam olarak bu bazı fonksiyonları sağlar gibi, sen şanslısın. setlocale() , usort() , strcoll() ve dil için doğru UTF-8 yereli bir arada kullanarak, böyle bir şey olsun:

$array = array('Àgile', 'Ágile', 'Âgile', 'Ãgile', 'Ägile', 'Agile', 'Test');
$oldLocal = setlocale(LC_COLLATE, '<<your_RFC1766_language_code>>.utf8');
usort($array, 'strcoll');
setlocale(LC_COLLATE, $oldLocal);

UTF-8 dizeleri sıralamak için UTF-8 yerel varyantı kullanmak zorunlu olduğunu unutmayınız. Daha fazla bilgi için PHP kılavuzuna bakınız - I setlocale() çalışan diğer PHP script yan etkilere neden olabilir kullanarak bir yerel ayarı olarak özgün değerine yukarıdaki örnekte yerel sıfırlayın.

Eğer bir Windows makine kullanırsanız, bu soruna no çözüm bulunmuyor ve PHP 6 önce herhangi Ben kabul olmaz. SO bu özel sorunu hedefleyen benim kendi question bakın.

Ben bu konu ile asort ile mücadele etti.

Sıralama:

Array
(
    [xa] => África
    [xo] => Australasia
    [cn] => China
    [gb] => Reino Unido
    [us] => Estados Unidos
    [ae] => Emiratos Árabes Unidos
    [jp] => Japón
    [lk] => Sri Lanka
    [xe] => Europa Del Este
    [xw] => Europa Del Oeste
    [fr] => Francia
    [de] => Alemania
    [be] => Bélgica
    [nl] => Holanda
    [es] => España
)

sonunda Afrika koydu. Ben bu kod kirli küçük parça (benim amaç ve benim süre için uygun olan) ile çözüldü:

$sort = array();
foreach($retval AS $key => $value) {
    $v = str_replace('ä', 'a', $value);
    $v = str_replace('Ä', 'A', $v);
    $v = str_replace('Á', 'A', $v);
    $v = str_replace('é', 'e', $v);
    $v = str_replace('ö', 'o', $v);
    $v = str_replace('ó', 'o', $v);
    $v = str_replace('Ö', 'O', $v);
    $v = str_replace('ü', 'u', $v);
    $v = str_replace('Ü', 'U', $v);
    $v = str_replace('ß', 'S', $v);
    $v = str_replace('ñ', 'n', $v);
    $sort[] = "$v|$key|$value";
}
sort($sort);

$retval = array();
foreach($sort AS $value) {
    $arr = explode('|', $value);
    $retval[$arr[1]] = $arr[2]; 
}