Як адсартаваць масіў UTF-8 радкоў у PHP?

патрэбна дапамога упарадкавана слоў на UTF-8. Напрыклад, у нас ёсць 5 гарадоў з Бельгіі.

$array = array('Borgloon','Thuin','Lennik','Éghezée','Aubel');
sort($array);//Expected: Aubel, Borgloon, Éghezée, Lennik, Thuin
             //Actual: Aubel, Borgloon, Lennik, Thuin, Éghezée

Горад <моцны> Эгезе павінен быць трэцім. Ці можна выкарыстоўваць/ўсталяваць нейкі UTF-8 або стварыць свой уласны парадак сымбаляў?

15
Дададзены каментарый, каб паменшыць блытаніну адносна таго, што вы шукаеце супраць таго, што вы атрымаеце.
дададзена аўтар Billy ONeal, крыніца
Я проста хацеў пазначыць на будучыню, што natcasesort не працуе з каробкі: codepad .org/QgdF5DUY
дададзена аўтар middus, крыніца
Падобна на тое, там быў падобны пытанне раней: stackoverflow.com/questions/120334/…
дададзена аўтар user1012851, крыніца

6 адказы

intl comes bundled with PHP from PHP 5.3 and it only supports UTF-8.

Вы можаце выкарыстоўваць Collator у гэтым выпадку:

$array = array('Borgloon','Thuin','Lennik','Éghezée','Aubel');
$collator = new Collator('en_US');
$collator->sort($array);
print_r($array);

выхад:

Array
(
    [0] => Aubel
    [1] => Borgloon
    [2] => Éghezée
    [3] => Lennik
    [4] => Thuin
)
29
дададзена

Я думаю, што вы можаце выкарыстоўваць strcoll :

setlocale(LC_COLLATE, 'nl_BE.utf8');
$array = array('Borgloon','Thuin','Lennik','Éghezée','Aubel');
usort($array, 'strcoll'); 
print_r($array);

Вынік:

Array
(
    [0] => Aubel
    [1] => Borgloon
    [2] => Éghezée
    [3] => Lennik
    [4] => Thuin
)

Вам трэба лакаль nl_BE.utf8 на вашай сістэме:

[email protected]:~$ locale -a | grep nl_BE.utf8
nl_BE.utf8

Калі вы выкарыстоўваеце Debian вы можаце выкарыстоўваць DPKG --reconfigure лакалі , каб дадаць лакалі.

9
дададзена
strcoll не працуе на Windows, з UTF-8, з-за ЭПТ падробленай рэалізацыяй
дададзена аўтар Enyby, крыніца
Чыстае рашэнне да гэтага часу.
дададзена аўтар Jaison Erick, крыніца
Рашэнне тайцаў для PHP 5,3 здаецца чыстай занадта
дададзена аўтар Fy-, крыніца

Гэты скрыпт павінен вырашыць у карыстацкім шляху. Я спадзяюся, што гэта дапаможа. Звярніце ўвагу на функцыю mb_strtolower. Вы павінны выкарыстоўваць гэта робяць функцыі адчувальныя да рэгістра. Прычына, чаму я не выкарыстаў функцыю strtolower з'яўляецца тое, што яна не вельмі добра працуе з адмысловымі Гольца.

<?php

function customSort($a, $b) {
    static $charOrder = array('a', 'b', 'c', 'd', 'e', 'é',
                              'f', 'g', 'h', 'i', 'j',
                              'k', 'l', 'm', 'n', 'o',
                              'p', 'q', 'r', 's', 't',
                              'u', 'v', 'w', 'x', 'y', 'z');

    $a = mb_strtolower($a);
    $b = mb_strtolower($b);

    for($i=0;$i $valB) return 1;
        return -1;
    }

    if(mb_strlen($a) == mb_strlen($b)) return 0;
    if(mb_strlen($a) > mb_strlen($b))  return -1;
    return 1;

}
$array = array('Borgloon','Thuin','Lennik','Éghezée','Aubel');
usort($array, 'customSort');

EDIT: На жаль. Я зрабіў шмат памылак у апошнім кодзе. Зараз тэстуецца.

EDIT {2}: Усе з функцыямі мультибайтных.

5
дададзена
+1, для вырашэння табліцы пошуку.
дададзена аўтар Billy ONeal, крыніца
На жаль, гэта не будзе працаваць, так як $ а [$ I] вяртае адзін байт з радка, а не адзін знак.
дададзена аўтар Leonid Shevtsov, крыніца
<Код> str_split не апрацоўвае многобайтовые радкі, а таксама. :) Глядзіце php.net/manual/en/function.mb -split.php # 99851
дададзена аўтар Leonid Shevtsov, крыніца
не запускаць функцыю STRLEN, што часта, вам трэба толькі запусціць іх калісьці загадзя, і вы ўжо можаце атрымаць мін значэння абодвух.
дададзена аўтар hakre, крыніца
Перад тым, так, вы маеце рацыю. Я змяніў алгарытм некалькі хвілін таму. Выкарыстанне str_split будзе працаваць.
дададзена аўтар Jaison Erick, крыніца
Ты маеш рацыю. Я абнавіў ў многобайтовый ўсюды.
дададзена аўтар Jaison Erick, крыніца

Што тычыцца strcoll я мяркую, што гэта была добрая ідэя, але не падобна на працу:

<?php

// Some 
$strings = array('Alpha', 'Älpha', 'Bravo');
// make it German: A, Ä, B
setlocale(LC_COLLATE, 'de_DE.UTF8', 'de.UTF8', 'de_DE.UTF-8', 'de.UTF-8');
usort($strings, 'strcoll');
var_dump($strings);
// as you can see, Ä is last, so this didn't work

Некаторы час таму я напісаў UTF-8 у ASCII інструмент , які будзе канвертаваць «Альф # бла» у «aelph -bla ». Вы можаце выкарыстоўваць гэта, каб «нармалізаваць» ўвод, каб зрабіць яго упарадкавана. Гэта ў асноўным замена падобна на тое, што сказаў @Nick.

Вы павінны выкарыстоўваць асобны масіў для сартавання, як выклік urlify() у usort() зваротнага выкліку будзе марнаваць шмат рэсурсаў. спрабаваць

<?php
// data to sort
$array = array('Borgloon','Thuin','Lennik','Éghezée','Aubel');
// container for modified strings
$_array = array();
foreach ($array as $k => $v) {
   //"normalize" utf8 to ascii
    $_array[$k] = urlify($v);
}
// sort the ASCII stuff (while preserving indexes)
asort($_array);
foreach ($_array as $key => &$v) {
   //copy the original value of the ASCIIfied element
    $v = $array[$k];
}
var_dump($_array);

Калі ў вас ёсць PHP5.3 або міжнар PECL кампілюецца, паспрабуйце @ рашэнне тайцаў, здаецца салодкім!

1
дададзена

Я быў бы спакуса Перабярыце масіў і пераўтварыць ангельскія сімвалы перад упарадкавана. напрыклад

<?php
  $array = array('Borgloon','Thuin','Lennik','Éghezée','Aubel');

  setlocale(LC_CTYPE, 'nl_BE.utf8');

  $newarray = array();
  foreach($array as $k => $v) {
    $newarray[$k] = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $v);
  }

  sort($newarray);
  print_r($newarray);
?>

Магчыма, не самы лепшы з пункту гледжання хуткасці апрацоўкі/выкарыстання рэсурсаў. Але ўпэўнены, што робіць яго лягчэй зразумець код.

<Моцны> Edit:

Думаючы пра гэта цяпер, вы маглі б быць лепш выкарыстоўваць нейкі табліцы пошуку, нешта накшталт гэтага:

<?php
  $accentedCharacters = array ( 'à', 'á', 'â', 'ã', 'ä', 'å', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Š', 'Ž', 'š', 'ž', 'Ÿ', 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý' ); 

  $replacementCharacters = array ( 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'y', 'S', 'Z', 's', 'z', 'Y', 'A', 'A', 'A', 'A', 'A', 'A', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y' );

  $array = array('Borgloon','Thuin','Lennik','Éghezée','Aubel');

  $newarray = array();
  foreach($array as $k => $v) {
    $newarray[$k] = str_replace($accentedCharacters,$replacementCharacters,$v);
  }

  sort($newarray);
  print_r($newarray);
?>
1
дададзена
Шчыра кажучы, гэта быў першы мову, які прыйшоў на розум, што будзе працаваць пры ўмове, што набор дадзеных. Думаючы пра гэта цяпер, ён мог бы быць лепш, выкарыстоўваючы даведачную табліцу пераўтварэнні замест таго, каб, калі набор дадзеных будуць выкарыстоўваць іншыя няправільныя сімвалы.
дададзена аўтар Nick, крыніца
Чаму вы прапануеце nl_BE ? (Галандская, як кажуць/запісана ў Бельгіі)
дададзена аўтар middus, крыніца

Калі вы хочаце выкарыстоўваць убудаваныя рашэння, так што я магу прапанаваць гэтую

function compare($a, $b)
{
        $alphabet = 'aąbcćdeęfghijklłmnnoóqprstuvwxyzźż';//i used polish letters
        $a = mb_strtolower($a);
        $b = mb_strtolower($b);

        for ($i = 0; $i < mb_strlen($a); $i++) {
            if (mb_substr($a, $i, 1) == mb_substr($b, $i, 1)) {
                continue;
            }
            if ($i > mb_strlen($b)) {
                return 1;
            }
            if (mb_strpos($alphabet, mb_substr($a, $i, 1)) > mb_strpos($alphabet, mb_substr($b, $i, 1))) {
                return 1;
            } else {
                return -1;
            }
        }
}

usort($needed_array, 'compare');

Не ўпэўнены, што гэта лепшае рашэнне, але гэта працуе для мяне =)

1
дададзена
добры, вялікі.
дададзена аўтар Eir, крыніца
Невялікае абнаўленне звязана з PHP 7 і новага аператара «касмічны карабель». Вы можаце выкарыстоўваць <=> для вяртання 1 або -1 у апошнім стане.
дададзена аўтар Amir Djaminov, крыніца