PHP почти естественная сортировка по фамилиям: три неправильно из 500+? [Дубликат]

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

Лучший способ подумать об этом процессе - это как будто вы генерируя текстовый файл динамически. Текст, который вы генерируете, становится исполняемым кодом после того, как браузер интерпретирует его. Только то, что вы размещаете между тегами <?php, оценивается на сервере.

Кстати, создание привычки встраивать случайные фрагменты PHP-логики в HTML или Javascript может привести к серьезному запутанному коду. Я говорю от болезненного опыта.

23
задан chills42 5 November 2008 в 15:35
поделиться

7 ответов

I нашел эту следующую вспомогательную функцию , чтобы преобразовать все буквы строки в буквы ASCII, очень полезные здесь.

function _all_letters_to_ASCII($string) {
  return strtr(utf8_decode($string), 
    utf8_decode('ŠŒŽšœžŸ¥µÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ'),
    'SOZsozYYuAAAAAAACEEEEIIIIDNOOOOOOUUUUYsaaaaaaaceeeeiiiionoooooouuuuyy');
}

После этого простой array_multisort() дает вам то, что вы хотите.

$array = array('Birnen', 'Äpfel', 'Ungetüme', 'Apfel', 'Ungetiere', 'Österreich');
$reference_array = $array;

foreach ($reference_array as $key => &$value) {
  $value = _all_letters_to_ASCII($value);
}
var_dump($reference_array);

array_multisort($reference_array, $array);
var_dump($array);

Конечно, вы можете сделать вспомогательную функцию более совершенной. Но пока это выглядит неплохо.

array(6) {
  [0]=> string(6) "Birnen"
  [1]=> string(5) "Apfel"
  [2]=> string(8) "Ungetume"
  [3]=> string(5) "Apfel"
  [4]=> string(9) "Ungetiere"
  [5]=> string(10) "Osterreich"
}

array(6) {
  [0]=> string(5) "Apfel"
  [1]=> string(6) "Äpfel"
  [2]=> string(6) "Birnen"
  [3]=> string(11) "Österreich"
  [4]=> string(9) "Ungetiere"
  [5]=> string(9) "Ungetüme"
}
0
ответ дан Community 25 August 2018 в 14:48
поделиться
$a = array( 'Кръстев', 'Делян1', 'делян1', 'Делян2', 'делян3', 'кръстев' );
$col = new \Collator('bg_BG');
$col->asort( $a );
var_dump( $a );

Отпечатки:

array
  2 => string 'делян1' (length=11)
  1 => string 'Делян1' (length=11)
  3 => string 'Делян2' (length=11)
  4 => string 'делян3' (length=11)
  5 => string 'кръстев' (length=14)
  0 => string 'Кръстев' (length=14)

Класс Collator определен в расширении int PECL . Он распространяется с источниками PHP 5.3, но может быть отключен для некоторых сборок. Например. в Debian он находится в пакете php5-intl.

Collator::compare полезен для usort.

26
ответ дан Delian Krustev 25 August 2018 в 14:48
поделиться
  • 1
    Расширение ext/intl было на самом деле моей спасательной программой - к сожалению, это не так просто установить на некоторых системах (например, Mac OS X с включенным PHP). – Stefan Gehrig 6 March 2012 в 10:17
  • 2
    Я часто развиваюсь на маке, и я никогда не использую в комплекте, например. LAMP. Вместо этого установите из чего-то вроде homebrew или macports, и вы сэкономите некоторые проблемы (и, вероятно, добавите немного больше, но это будет меньшая сумма проблем) – chrishiestand 3 October 2013 в 00:14

Использование вашего примера с кодовой страницей 1252 отлично работало на моей машине разработки Windows.

$array=array('Birnen', 'Äpfel', 'Ungetüme', 'Apfel', 'Ungetiere', 'Österreich');
$oldLocal=setlocale(LC_COLLATE, "0");
var_dump(setlocale(LC_COLLATE, 'German_Germany.1252'));
usort($array, 'strcoll');
var_dump(setlocale(LC_COLLATE, $oldLocal));
var_dump($array);

... snip ...

Это было с PHP 5.2.6. Кстати. Вышеприведенный пример неверен, он использует кодировку ASCII вместо UTF-8. Я проследил вызовы strcoll () и посмотрел, что я нашел:

function traceStrColl($a, $b) {
    $outValue = strcoll($a, $b);
    echo "$a $b $outValue\r\n";
    return $outValue;
}

$array=array('Birnen', 'Äpfel', 'Ungetüme', 'Apfel', 'Ungetiere', 'Österreich');
setlocale(LC_COLLATE, 'German_Germany.65001');
usort($array, 'traceStrColl');
print_r($array);

дает:

Ungetüme Äpfel 2147483647
Ungetüme Birnen 2147483647
Ungetüme Apfel 2147483647
Ungetüme Ungetiere 2147483647
Österreich Ungetüme 2147483647
Äpfel Ungetiere 2147483647
Äpfel Birnen 2147483647
Apfel Äpfel 2147483647
Ungetiere Birnen 2147483647

Я нашел некоторые сообщения об ошибках , которые были отмечены как bogus ... Лучшая ставка у вас есть подача отчета об ошибке, я полагаю, хотя ...

0
ответ дан Huppie 25 August 2018 в 14:48
поделиться
  • 1
    Вы уверены, что ваш PHP-файл, используемый для тестирования, кодируется UTF-8? Если я использую кодировку ISO-8859-1 для самого файла, я получаю тот же результат, который вы указали выше. – Stefan Gehrig 23 September 2008 в 12:29
  • 2
    Я дважды свернул его со вторым файлом (убедился, что он был кодирован в кодировке UTF-8), но теперь он (действительно), похоже, реплицирует вашу проблему, извините за дерьмо в этом случае. – Huppie 23 September 2008 в 12:32

Я столкнулся с той же проблемой с немецким «Умлаут». После некоторых исследований это сработало для меня:

$laender =array("Österreich", "Schweiz", "England", "France", "Ägypten");  
$laender = array_map("utf8_decode", $laender);  
setlocale(LC_ALL,"de_DE@euro", "de_DE", "deu_deu");  
sort($laender, SORT_LOCALE_STRING);  
$laender = array_map("utf8_encode", $laender);  
print_r($laender);

Результат:

Array ([0] => Ägypten [1] => Англия [2] = > Франция [3] => Österreich [4] => Schweiz)

0
ответ дан Misa Lazovic 25 August 2018 в 14:48
поделиться
  • 1
    Проблема здесь в том, что вы собираетесь потерять символы, которые не могут быть представлены в ISO-8859-1. – Stefan Gehrig 11 October 2016 в 10:55

В конечном счете эта проблема не может быть решена простым способом без использования перекодированных строк (UTF-8 → Windows-1252 или ISO-8859-1), как это было предложено ΤΖΩΤΖΙΟΥ из-за очевидной ошибки PHP, обнаруженной Huppie. Чтобы обобщить эту проблему, я создал следующий фрагмент кода, который наглядно демонстрирует, что проблема связана с функцией strcoll () при использовании кодовой страницы Windows-UTF-8 65001.

function traceStrColl($a, $b) {
    $outValue=strcoll($a, $b);
    echo "$a $b $outValue\r\n";
    return $outValue;
}

$locale=(defined('PHP_OS') && stristr(PHP_OS, 'win')) ? 'German_Germany.65001' : 'de_DE.utf8';

$string="ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜabcdefghijklmnopqrstuvwxyzäöüß";
$array=array();
for ($i=0; $i<mb_strlen($string, 'UTF-8'); $i++) {
    $array[]=mb_substr($string, $i, 1, 'UTF-8');
}
$oldLocale=setlocale(LC_COLLATE, "0");
var_dump(setlocale(LC_COLLATE, $locale));
usort($array, 'traceStrColl');
setlocale(LC_COLLATE, $oldLocale);
var_dump($array);

Результат:

string(20) "German_Germany.65001"
a B 2147483647
[...]
array(59) {
  [0]=>
  string(1) "c"
  [1]=>
  string(1) "B"
  [2]=>
  string(1) "s"
  [3]=>
  string(1) "C"
  [4]=>
  string(1) "k"
  [5]=>
  string(1) "D"
  [6]=>
  string(2) "ä"
  [7]=>
  string(1) "E"
  [8]=>
  string(1) "g"
  [...]

Тот же фрагмент работает на машине Linux без каких-либо проблем, создавая следующий вывод:

string(10) "de_DE.utf8"
a B -1
[...]
array(59) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "A"
  [2]=>
  string(2) "ä"
  [3]=>
  string(2) "Ä"
  [4]=>
  string(1) "b"
  [5]=>
  string(1) "B"
  [6]=>
  string(1) "c"
  [7]=>
  string(1) "C"
  [...]

Фрагмент также работает при использовании Windows-1252 (ISO-8859-1 ) закодированные строки (конечно, кодировки mb_ * и локаль должны быть изменены затем).

Я отправил отчет об ошибке на bugs.php.net : Ошибка # 46165 strcoll () не работает с строками UTF-8 в Windows . Если у вас возникла та же проблема, вы можете дать свои отзывы команде PHP на странице отчета об ошибке (две другие, возможно связанные с этим, ошибки были классифицированы как bogus - я не думаю, что это ошибка bogus ; -).

Спасибо всем вам.

6
ответ дан Stefan Gehrig 25 August 2018 в 14:48
поделиться
  • 1
    Ваш отчет об ошибке получил мой голос ;-) – Huppie 24 September 2008 в 19:29
  • 2
    Это является ошибкой в ​​PHP, чтобы полагаться на способность ОС правильно сортировать строки, зная, что некоторые ОС не будут. Если тонкой оболочки недостаточно, PHP должен использовать что-то еще. – matteo 5 August 2012 в 13:46
  • 3
    Список локалей: docs.moodle.org/dev/Table_of_locales – Nuri Akman 11 March 2014 в 16:46

Ваша сортировка должна соответствовать набору символов. Поскольку ваши данные кодируются в кодировке UTF-8, вы должны использовать сортировку UTF-8.

В системах UNIX вы можете получить список локально установленных локалей с помощью команды

locale -a
-1
ответ дан troelskn 25 August 2018 в 14:48
поделиться
  • 1
    Я использую Windows-машину для разработки ... Соответствующая кодовая страница UTF-8 в Windows - 65001 - вот почему мой язык должен быть German_Germany.65001. – Stefan Gehrig 23 September 2008 в 17:21

Это очень сложная проблема , поскольку кодированные данные UTF-8 могут содержать любой символ Юникода (т. е. символы из многих 8-битных кодировок, которые различаются по разному в разных локалях).

Возможно, если вы преобразовали ваши данные UTF-8 в Unicode (не знакомы с функциями юникода PHP, извините), а затем нормализовали их в NFD или NFKD , а затем сортировка по кодовым точкам может дать некоторую сортировку, которая («A» перед «Ä»).

Проверьте ссылки, которые я предоставил.

EDIT: поскольку вы упоминаете, что ваши входные данные ясны (я предполагаю, что они все они попадают в кодовую страницу «windows-1252»), тогда вы должны сделать следующее преобразование: UTF-8 → Юникод → Windows-1252, на котором закодированные данные Windows-1252 выполняют сортировку, выбрав локаль «CP1252».

3
ответ дан tzot 25 August 2018 в 14:48
поделиться
  • 1
    Спасибо за эту информацию - я посмотрю ссылки. Но я сомневаюсь, что это результат стоит того, что я просто хочу, чтобы отсортировать список названий стран и штатов. Возможно, существует более простое решение. – Stefan Gehrig 23 September 2008 в 12:35
  • 2
    Кажется, это разумное решение ... Я попробую сортировать преобразованный массив. Вы правы, что Windows-1252 должен охватывать все используемые символы. – Stefan Gehrig 23 September 2008 в 13:20
  • 3
    Что значит конвертировать UTF-8 в Unicode. UTF-8 - кодировка символов переменной длины для Unicode. – grom 23 September 2008 в 13:46
  • 4
    Я имею в виду строку байтов кодовых точек Юникода, кодированную как UTF-8, во внутреннее представление как строку кодов Unicode, независимо от того, что это было бы в PHP (будь то UCS-2, UCS-4). Я предполагаю, что PHP имеет такую ​​концепцию. – tzot 23 September 2008 в 20:41
  • 5
    Большое вам спасибо за это, я добавлю его в качестве ссылки. – Alix Axel 11 August 2009 в 00:11
Другие вопросы по тегам:

Похожие вопросы: