Сортировка с использованием символов utf в mysql или php? лучшие решения
Используя MySQL, я выбираю список песен на испанском языке, которые я хотел бы отсортировать. Вот список имен, возвращаемых запросом:
- ¡Дециревилья!
- Альгамбра
- 123 пасито
- Африка
- Арроз
- Децир
Отсортированный список должен выглядеть следующим образом:
- 123 пасито
- Африка
- Альгамбра
- Арроз
- ¡Дециревилья!
- Децир
После всех исследований, которые я провел прочитав, я пришел к выводу, что нет разумного способа добиться этого с помощью MySQL. Я пробовал сопоставление, кодировку и т. Д... но нет никакого способа, чтобы персонаж ¡, ? и т.д.... мог быть отсортирован в соответствии с моим желаемым результатом. Даже А не сортируется так, как я хочу...
Вопрос 1: Является ли это разумным выводом?
Я считаю, что единственный способ добиться этого - передать результаты в массив на php, а затем отсортировать массив с помощью пользовательской функции... все это с помощью функции usort (нужно сортировать по значению, и я не забочусь о сохранении ключевой ассоциации). Что-то похожее на это:
function normalize($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$tracks = array();
while ($row = $result->fetch_assoc()) {
$tracks[] = $row;
}
usort($tracks, 'normalize');
Вопрос 2: Это лучший способ добиться пользовательской сортировки?
Вот где я упираюсь в стену:
Вопрос 3: Я понятия не имею, как создать функцию нормализации для сортировки имен в соответствии с моими потребностями. Как мне игнорировать определенные символы (¡, ?, ', !, ¿) и как мне заменить другие символы естественным эквивалентом (Á -> A, É -> E и т. Д.) Я верю что, игнорируя определенные символы и заменяя другие, я могу добиться сортировки, которую ищу...
Вопрос 4: Все это имеет смысл? На правильном ли я пути?
Заранее спасибо за все ваши советы. Марко
2 answers
Вы можете добавить свои собственные параметры сортировки в MySQL. Тогда вы могли бы игнорировать любые символы, которые вам безразличны, расставлять акценты по мере необходимости и вообще сортировать вещи любым согласованным способом, который вы пожелаете.
Выполнение искаженной сортировки на стороне клиента (т.Е. в PHP, а не в базе данных) будет не так быстро, как в базе данных. Этот подход также с треском провалится, как только вам придется добавить предложения LIMIT
и OFFSET
в свой запрос. Я не уверен, что обычай параметры сортировки делают правильные вещи для MAX()
аналогичных функций, но выполнение искаженных параметров сортировки в PHP, безусловно, не будет, если вы не хотите просмотреть всю таблицу, отсортировать ее, а затем захватить только одну запись.
Итак, я бы рассмотрел возможность выполнения сортировки за пределами базы данных в качестве последнего средства.
Другой вариант, если вы не хотите создавать свои собственные параметры сортировки, - это создать искусственный столбец в вашей таблице, который выполняет правильную сортировку. Вы могли бы использовать функцию normalize()
в PHP-land (что-то вроде Джейкоба было бы разумной отправной точкой) и сохранить результат в базе данных в виде столбца, называемого, скажем, sortable_title
; тогда ORDER BY sortable_title
сделает свое дело. Вам нужна функция normalize()
PHP, которая создавала бы такой список (без знаков препинания, все в нижнем регистре, без акцентов, ...):
- 123 пасито
- африка
- альгамбра
- арроз
- дециревилла
- децир
Так что простая сортировка в формате ASCII будет правильной. Конечно, вы бы необходимо инициализировать sortable_title
при выполнении вставок и восстанавливать его во время обновлений, но это должно быть довольно просто, если ваш код правильно инкапсулирован.
Вопрос 4: Я думаю, что не соглашусь с Джейкобом и скажу, что вы идете в неправильном направлении, удаляя параметры сортировки из базы данных. Я не говорю, что вы полностью сбились с пути, но вам лучше позволить MySQL обрабатывать сортировку, даже если в конечном итоге вы можете оказать ему некоторую помощь с чем-то вроде sortable_title
взлом, описанный выше.
Вопрос 2. Это хороший способ добиться пользовательской сортировки, тогда единственная реальная работа, которую вам нужно выполнить, - это функция сравнения.
Вопрос 3.
Возможно, стоит преобразовать строку в ее эквивалент ASCII с помощью iconv
. Который может конвертировать UTF-8 в ASCII и, используя транслит, он будет соответствовать символу, который нельзя напрямую преобразовать во что-то похожее на него.
Т.е. Á -> A, É ->E и т. Д.
Как только он будет преобразован, вы сможете удалить символы, которые вы не хотите сортировать с помощью preg_replace или str_replace.
Вот пример функции сравнения, которую вы могли бы использовать.
function normalize_string($string) {
$ascii = iconv("utf-8","ascii//TRANSLIT", $string);
return str_replace(array('!', "'", '?'), '', $ascii);
// or
return preg_replace('/[!\'?]/', '', $ascii);
// or depending on how much you do want to replace... \W => any "non-word" character
return preg_replace('/\W/', '', $ascii);
}
function custom_str_cmp($a, $b) {
return strcmp(normalize_string($a), normalize_string($b));
}
usort($tracks, 'custom_str_cmp');
Вопрос 4. Да.