Как отсортировать массив строк UTF-8?

В качестве обходного пути вы можете просто заставить код, получающий POST, отвечать на данные приложения / json. Для PHP я добавил код ниже, разрешив мне POST для него либо в форме, либо в JSON.

//handles JSON posted arguments and stuffs them into $_POST
//angular's $http makes JSON posts (not normal "form encoded")
$content_type_args = explode(';', $_SERVER['CONTENT_TYPE']); //parse content_type string
if ($content_type_args[0] == 'application/json')
  $_POST = json_decode(file_get_contents('php://input'),true);

//now continue to reference $_POST vars as usual
25
задан chills42 5 November 2008 в 14:35
поделиться

5 ответов

В конечном счете эта проблема не может быть решена простым способом, не используя повторно кодированные строки (UTF-8 в †’ Windows 1252 или ISO-8859-1), как предложено О¤О–О©О¤О–О™ОџОҐ из-за очевидной ошибки PHP, как обнаружено Huppie. Для суммирования проблемы я создал следующий фрагмент кода, который ясно демонстрирует, что проблемой является strcoll () функция при использовании 65 001 Windows-UTF-8-codepage.

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 на странице отчета об ошибках (два другой, вероятно, связанный, ошибки были классифицированы как поддельный - я не думаю, что эта ошибка поддельная ;-).

Благодаря всем Вам.

6
ответ дан Stefan Gehrig 28 November 2019 в 07:16
поделиться

Обновление по этой проблеме:

Даже при том, что дискуссия по поводу этой проблемы показала, что мы, возможно, обнаружили ошибку PHP с strcoll() и/или setlocale() , это - ясно не случай. Проблемой является скорее ограничение реализации Windows CRT setlocale() (PHPs setlocale() является просто тонкой оберткой вокруг вызова CRT). Следующее является цитатой страница MSDN "setlocale, _wsetlocale" :

набор доступных языков, кодов страны/региона и кодовых страниц включает все поддерживаемые Win32 NLS API кроме кодовых страниц, которые требуют больше чем двух байтов за символ, таких как UTF-7 и UTF-8. Если Вы предоставляете кодовую страницу как UTF-7, или UTF-8, setlocale перестанет работать, возвращая ПУСТОЙ УКАЗАТЕЛЬ. набор языка и кодов страны/региона, поддерживаемых setlocale, перечислен в Строках Языка и Страны/Региона.

поэтому невозможно использовать осведомленные о локали строковые операции в PHP в Windows, когда строки многобайтовые закодированный.

8
ответ дан Stefan Gehrig 28 November 2019 в 07:16
поделиться

Используя Ваш пример с кодовой страницей 1252, работавшей превосходный здесь на моей машине разработки окон.

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

... надрез...

Это было с PHP 5.2.6. btw.

<час> вышеупомянутый пример неправильный , это использует кодирование 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

я действительно находил [приблизительно 113] отчеты об ошибках , которые были отмечены, будучи поддельными ... Лучший выбор, который Вы имеете, регистрирует отчет об ошибках, который я предполагаю хотя...

0
ответ дан Huppie 28 November 2019 в 07:16
поделиться

Ваше сопоставление должно соответствовать набору символов. Так как Ваши данные являются закодированным UTF-8, необходимо использовать сопоставление UTF-8. Это можно было назвать по-другому на различных платформах, но хорошее предположение будет de_DE.utf8.

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

locale -a
-1
ответ дан troelskn 28 November 2019 в 07:16
поделиться

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

, Возможно, если Вы преобразовали свои данные UTF-8 в Unicode (не знакомый с PHP unicode функции, извините) и затем нормализовали их в , NFD или NFKD и затем сортирующий на кодовых точках могли бы дать некоторое сопоставление, которое будет иметь смысл Вам (т.е. прежде "Г „").

Проверка ссылки я обеспечил.

РЕДАКТИРОВАНИЕ: так как Вы упоминаете, что Ваши входные данные ясны (я принимаю их всю осень в "кодовой странице" 1252 окон), тогда необходимо сделать следующее преобразование: UTF-8 в †’ Unicode в †’ Windows 1252, по которому Windows 1252 закодировал данные, делает вид, выбирающий локаль "CP1252".

4
ответ дан tzot 28 November 2019 в 07:16
поделиться
Другие вопросы по тегам:

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