2009-05-07 11 views
19

क्या प्राकृतिक ऑर्डर एल्गोरिदम का उपयोग करके PHP में यूनिकोड/यूटीएफ -8 वर्णों के साथ सरणी को सॉर्ट करना संभव है? उदाहरण के लिए (इस सरणी में आदेश सही ढंग से आदेश दिया जाता है):यूनिकोड के समर्थन के साथ PHP में प्राकृतिक सॉर्टिंग एल्गोरिदम?

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

अगर मैं asort ($ सरणी) मैं निम्नलिखित परिणाम प्राप्त के साथ प्रयास करें:

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

और का उपयोग कर natsort ($ सरणी):

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

कैसे मैं एक समारोह है कि सही परिणाम आदेश देता है लागू कर सकते हैं (0, 1, 2, 3, 4, 5, 6) PHP 5 के तहत? सभी मल्टी बाइट स्ट्रिंग फ़ंक्शंस (mbstring, iconv, ...) मेरे सिस्टम पर उपलब्ध हैं।

संपादित करें: मैं मानों को नट्सोर्ट() करना चाहता हूं, चाबियाँ नहीं - एकमात्र कारण है कि मैं स्पष्ट रूप से कुंजी (और सॉर्ट() के बजाय एएसओआर() का उपयोग कर रहा हूं) खोजने का काम आसान करना है बाहर जहां यूनिकोड मानों का क्रमबद्ध गलत हो गया।

उत्तर

11

इसे खींचा!

$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); 

आउटपुट:

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

और भी बेहतर:

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

धन्यवाद @tchrist करने के लिए!

+3

लगता है कि आपको वास्तव में यहां क्या चाहिए, यूनिकोड कोलेशन एल्गोरिदम (यूसीए) है। मेरे पास एक पर्ल प्रदर्शन है [इस जवाब में] (http://stackoverflow.com/questions/1097908/how-do-i-sort-unicode-strings-alphabetically-in-python/5024116#5024116), जहां मैं उन लोगों के लिए एक शेल-कॉल करने योग्य संस्करण प्रदान करें जिनके पास कॉल करने के लिए उचित लाइब्रेरी नहीं हो सकती है। शायद यह भी यहां मदद कर सकता है। – tchrist

+0

@ क्रिसमस: यूसीए जो मैं ढूंढ रहा हूं, मैं थोड़ा सा जवाब दूंगा, सिर के लिए धन्यवाद! ;) –

1
natsort($array); 
$array = array_values($array); 
+0

अच्छा एक। मेरा वोट मिला। – Babiker

+0

मेरे उदाहरण में कुंजी समस्या नहीं हैं, वे केवल यूनिकोड मानों को क्रमबद्ध करने में मदद करने के लिए हैं। –

24

प्रश्न के रूप में यह पहली नज़र पर लगता है जवाब देने के लिए के रूप में आसान नहीं है। यह उन क्षेत्रों में से एक है जहां PHP की यूनिकोड समर्थन की कमी आपको पूर्ण शक्ति के साथ हिट करती है।

अन्य पोस्टर्स द्वारा सुझाए गए सभी natsort() की फ्रिस्ट के प्रकार के प्रकार को सॉर्ट करने के लिए कुछ भी नहीं है जिसे आप सॉर्ट करना चाहते हैं। जो आप खोज रहे हैं वह एक स्थानीय जागरूक सॉर्टिंग तंत्र है क्योंकि विस्तारित वर्णों के साथ तारों को सॉर्ट करना हमेशा उपयोग की जाने वाली भाषा का प्रश्न है। उदाहरण के लिए जर्मन लेते हैं: ए और कभी-कभी हल किया जा सकता है जैसे कि वे एक ही अक्षर (डीआईएन 5007/1) थे, और कभी-कभी इसे हल किया जा सकता है क्योंकि यह वास्तव में "एई" (डीआईएन 5007/2) था। स्वीडिश में, इसके विपरीत, वर्णमाला के अंत में आता है।

यदि आप विंडोज का उपयोग नहीं करते हैं, तो आप भाग्यशाली हैं क्योंकि PHP वास्तव में कुछ फ़ंक्शंस प्रदान करता है। setlocale(), usort(), strcoll() का एक संयोजन और अपनी भाषा के लिए सही UTF-8 लोकेल उपयोग करके, आप कुछ इस तरह मिलती है:

$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 लोकेल भिन्न रूप का उपयोग करने के लिए अनिवार्य है यूटीएफ -8 स्ट्रिंग्स। मैंने उपरोक्त उदाहरण में लोकेल को अपने मूल मान पर रीसेट कर दिया है क्योंकि setlocale() का उपयोग करके लोकेल सेट करने से अन्य चल रहे PHP स्क्रिप्ट में दुष्प्रभाव लागू हो सकते हैं - कृपया अधिक जानकारी के लिए PHP मैन्युअल देखें।

जब आप विंडोज मशीन का उपयोग करते हैं, तो वर्तमान में कोई इस समस्या का हल नहीं है और मुझे लगता है कि PHP 6 से पहले कोई भी नहीं होगा। इस विशिष्ट समस्या को लक्षित करने के लिए कृपया अपना खुद का question देखें।

+1

महान अंतर्दृष्टि, मैं विंडोज़ पर विकास कर रहा हूं लेकिन यह * निक्स मशीनों पर चल जाएगा। अगर मुझे गलत नहीं लगता है तो PHP 5.3 इस तरह के सॉर्टिंग का समर्थन करेगा हालांकि कुछ प्रकार की कक्षा हालांकि मैं खुद को set_locale() पर अधिकतर कारणों से भरोसा करने से बचना चाहता हूं: 1) यह अप्रत्याशित है (ओएस उपलब्ध लोकेशंस पर निर्भर करता है) और 2) यह थ्रेड-सुरक्षित नहीं है और सर्वर पर अप्रत्याशित व्यवहार कर सकता है। –

+0

ord() फ़ंक्शन के एक बहु बाइट संस्करण का उपयोग करके सॉर्टिंग मुझे एक साधारण सॉर्ट() के समान परिणाम देता है। = ( –

+0

क्षमा करें, लेकिन मैं आपकी दूसरी टिप्पणी का पालन नहीं कर सकता ... –

0

मैं इस मुद्दे के साथ asort के साथ संघर्ष किया।

सॉर्ट:

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 
) 

अंत में अफ्रीका डाल दिया।

$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]; 
} 
+0

क्या आप फ्रेंच हैं? आप इस प्रश्न का मेरा जवाब जांचना चाहेंगे, मेरा 'preg_replace' दृष्टिकोण लिप्यंतरण थोड़ा बेहतर करता है और' array_multisort' फ़ंक्शन भी मानों और गैर-संख्यात्मक कुंजी के संयोजन को संरक्षित करता है। –

0

मैं भी उन setlocale के लिए एक और समाधान का काम नहीं करता है और intl मॉड्यूल की जरूरत नहीं है: मैं कोड के इस गंदे छोटा सा टुकड़ा (जो मेरा उद्देश्य और मेरे समय सीमा के ही योग्य है) के साथ इसे हल सक्षम:

// The array to be sorted 
$countries = array(
    'AT' => Österreich, 
    'DE' => Deutschland, 
    'CH' => Schweiz, 
); 

// Extend this array to your needs. 
$utf_sort_map = array(
    "ä" => "a", 
    "Ä" => "A", 
    "Å" => "A", 
    "ö" => "o", 
    "Ö" => "O", 
    "ü" => "u", 
    "Ü" => "U", 
); 

uasort($my_array, function($a, $b) use ($utf_sort_map) { 
    $initial_a = mb_substr($a, 0, 1); 
    $initial_b = mb_substr($b, 0, 1); 

    if (isset($utf_sort_map[$initial_a]) || isset($utf_sort_map[$initial_b])) { 
    if (isset($utf_sort_map[$initial_a])) { 
     $initial_a = $utf_sort_map[$initial_a]; 
    } 

    if (isset($utf_sort_map[$initial_b])) { 
     $initial_b = $utf_sort_map[$initial_b]; 
    } 

    if ($initial_a == $initial_b) { 
     return mb_substr($a, 1) < mb_substr($b, 1) ? -1 : 1; 
    } 
    else { 
     return $initial_a < $initial_b ? -1 : 1; 
    } 
    } 

    return $a < $b ? -1 : 1; 
}); 
संबंधित मुद्दे