Сортировка Strcoll UTF-8 — PHP

Итак, у меня есть этот массив, который необходимо отсортировать по алфавиту, игнорируя акценты (например, «e» должно стоять прямо перед «é», а за «a» должны следовать его варианты, например, «à»). Массив считывается из файла JSON, декодируется, организуется (или должен быть), затем кодируется обратно (для добавления объектов сотрудниками). Моя единственная проблема в том, что каждая буква с ударением ставится в конце. Вот пример моего кода:

$myArray = [
    {"myKey":"Aaa","values":[1,1,1,1,1,1,1]},
    {"myKey":"Test01","values":[1,1,1,1,1,1,1]},
    {"myKey":"Test02","values":[1,1,1,1,1,1,1]},
    {"myKey":"BBB","values":[1,1,1,1,1,1,1]},
    {"myKey":"Écha","values":[1,1,1,1,1,1,1]}
]

setlocale(LC_COLLATE, 'fr_CA.utf8');

usort($myArray, function($a, $b){ 
    return strcoll($a["myKey"], $b["myKey"]);
});

$myNewFile = json_encode($myArray,JSON_NUMERIC_CHECK|JSON_UNESCAPED_UNICODE);
echo $myNewFile;

Эхо дает:

[
    {"myKey":"Aaa","values":[1,1,1,1,1,1,1]},
    {"myKey":"BBB","values":[1,1,1,1,1,1,1]},
    {"myKey":"Test01","values":[1,1,1,1,1,1,1]},
    {"myKey":"Test02","values":[1,1,1,1,1,1,1]},
    {"myKey":"Écha","values":[1,1,1,1,1,1,1]}
]

Когда должно быть:

[
    {"myKey":"Aaa","values":[1,1,1,1,1,1,1]},
    {"myKey":"BBB","values":[1,1,1,1,1,1,1]},
    {"myKey":"Écha","values":[1,1,1,1,1,1,1]},
    {"myKey":"Test01","values":[1,1,1,1,1,1,1]},
    {"myKey":"Test02","values":[1,1,1,1,1,1,1]}
]

Я также пробовал следующее, так как изо всех сил старался найти существующее решение с несколькими сообщениями на эту тему:

$collator = new Collator('fr_CA.utf8');
$collator->sort($myArray);

и (не обязательно, так как я на PHP 7+, но я в отчаянии)

usort($myArray["Ingrédients"], 'custom_sort');

function custom_sort(($a, $b){ 
    return strcoll($a["Ingrédients"], $b["Ingrédients"]); 
});

и (так как я на PHP 7+)

usort($myArray, function($a, $b) {
    return $a['myKey'] <=> $b['myKey'];
});

Я также использовал разные коды стран для своего setlocale, например

'fr_CA.utf8', 'fr_FR.utf8', 'fr_CA', 'fr_FR'

Каждый из этих методов, кажется, работает для всех во всех сообщениях, которые я видел до сих пор, но они довольно устарели. Все они работают, кроме сортировки акцентов, поэтому я получаю тот же результат, что и получаю, независимо от метода. Сервер работает на PHP 7.1.1, если это поможет. Я действительно в тупике, и было бы очень здорово, если бы кто-нибудь знал, как это исправить, или имел какое-то просветление, которое можно было бы предложить.

Спасибо!

РЕДАКТИРОВАНИЕ / РЕШЕНИЕ:

Это все тот же usort, но с добавленной заменой букв с диакритическими знаками. Это содержит только символы для французского языка, но вы поняли идею.

usort($myArray, function($a, $b) {
    $translit = array('Á'=>'A','À'=>'A','Â'=>'A','Ä'=>'A','Ã'=>'A','Å'=>'A','Ç'=>'C','É'=>'E','È'=>'E','Ê'=>'E','Ë'=>'E','Í'=>'I','Ï'=>'I','Î'=>'I','Ì'=>'I','Ñ'=>'N','Ó'=>'O','Ò'=>'O','Ô'=>'O','Ö'=>'O','Õ'=>'O','Ú'=>'U','Ù'=>'U','Û'=>'U','Ü'=>'U','Ý'=>'Y','á'=>'a','à'=>'a','â'=>'a','ä'=>'a','ã'=>'a','å'=>'a','ç'=>'c','é'=>'e','è'=>'e','ê'=>'e','ë'=>'e','í'=>'i','ì'=>'i','î'=>'i','ï'=>'i','ñ'=>'n','ó'=>'o','ò'=>'o','ô'=>'o','ö'=>'o','õ'=>'o','ú'=>'u','ù'=>'u','û'=>'u','ü'=>'u','ý'=>'y','ÿ'=>'y');
    $at = strtr($a['myKey'], $translit);
    $bt = strtr($b['myKey'], $translit);
    return strcoll($at, $bt);
});

Надеюсь, это поможет в будущем!


person Christophe Stapinsky    schedule 25.04.2017    source источник


Ответы (1)


Итак, вкратце, проблема у вас связана с ценностью персонажа. strcoll сравнивает строки на основе значений их символов для используемого вами набора символов. Я предполагаю, что вы используете utf-8 или что-то очень похожее. См. значения UTF-8. Обратите внимание, как значение e со знаком ударения намного выше, чем Z? Вот почему у вас возникла эта проблема. Чтобы исправить это, вам придется добавить специальные регистры для акцентированных символов, так как в противном случае обычная сортировка не работает. Итак, в основном, создайте свою собственную функцию сравнения, которая поставит букву e со знаком ударения там, где обычно стоит f, и так далее.

person Nathaniel Blakely    schedule 25.04.2017
comment
Это на самом деле имеет большой смысл, спасибо. Я получу право на это! - person Christophe Stapinsky; 25.04.2017
comment
Без проблем. Кроме того, поскольку вы здесь впервые, см. stackoverflow.com/help/someone-answers. - person Nathaniel Blakely; 25.04.2017
comment
Я обновлю ОП для всех, кто заинтересован, и в качестве справочного материала в будущем. Я нашел решение после долгих исследований французского форума, датированного 2012 годом, после того, как моя функция замены фактически заменила текст вместо значения. - person Christophe Stapinsky; 27.04.2017