当前位置:  开发笔记 > 编程语言 > 正文

如何对UTF-8字符串数组进行排序?

如何解决《如何对UTF-8字符串数组进行排序?》经验,为你挑选了3个好方法。

我currentyl对如何在PHP中对包含UTF-8编码字符串的数组进行排序没有任何线索.该阵列来自LDAP服务器,因此通过数据库排序(没有问题)是没有解决方案.以下不适用于我的Windows开发机器(虽然我认为这至少应该是一个可能的解决方案):

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

输出是:

string(20) "German_Germany.65001"
string(1) "C"
array(6) {
  [0]=>
  string(6) "Birnen"
  [1]=>
  string(9) "Ungetiere"
  [2]=>
  string(6) "Äpfel"
  [3]=>
  string(5) "Apfel"
  [4]=>
  string(9) "Ungetüme"
  [5]=>
  string(11) "Österreich"
}

这完全是胡说八道.使用1252作为代码页setlocale()给出了另一个输出,但仍然是一个明显错误的输出:

string(19) "German_Germany.1252"
string(1) "C"
array(6) {
  [0]=>
  string(11) "Österreich"
  [1]=>
  string(6) "Äpfel"
  [2]=>
  string(5) "Apfel"
  [3]=>
  string(6) "Birnen"
  [4]=>
  string(9) "Ungetüme"
  [5]=>
  string(9) "Ungetiere"
}

有没有办法用UTF-8字符串区域设置识别数组?

刚才注意到这似乎是PHP上的问题,因为de_DE.utf8用作locale 的相同代码段可以在Linux机器上运行.不过,这个特定于Windows的问题的解决方案会很好......



1> Delian Krust..:
$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类中定义PECL国际延伸.它与PHP 5.3源一起分发,但某些版本可能会被禁用.例如在Debian中它是在包php5-intl中.

Collator::compare是有用的usort.


`ext/intl`扩展实际上是我的救生员 - 不幸的是,在某些系统上安装并不是那么容易(例如,带有捆绑PHP的Mac OS X).

2> Stefan Gehri..:

有关此问题的更新:

尽管围绕这个问题的讨论显示我们可能已经发现了PHP错误strcoll()和/或setlocale(),但事实显然并非如此.问题在于Windows CRT实现的限制setlocale()(PHP setlocale()只是围绕CRT调用的一个薄包装).以下是MSDN页面"setlocale,_wsetlocale"的引用:

可用语言,国家/地区代码和代码页的集合包括Win32 NLS API支持的所有内容,但每个字符需要两个以上字节的代码页除外,例如UTF-7和UTF-8.如果您提供类似UTF-7或UTF-8的代码页,则setlocale将失败,返回NULL.语言和国家/地区字符串中列出了setlocale支持的语言和国家/地区代码集.

因此,当字符串是多字节编码时,不可能在Windows上的PHP中使用区域设置感知字符串操作.


它是PHP中的一个错误,它依赖于操作系统正确整理字符串的能力,知道某些操作系统不会.如果瘦包装不够,PHP应该使用其他东西.

3> Stefan Gehri..:

最终,由于Huppie发现的一个明显的PHP错误,如果不使用ΤΖΩΤΖΙΟΥ建议的重新编码字符串(UTF-8→Windows-1252或ISO-8859-1),这个问题无法以简单的方式解决.为了总结这个问题,我创建了以下代码片段,它清楚地表明问题是使用65001 Windows-UTF-8代码页时的strcoll()函数.

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

结果是:

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上提交了一个bug报告:Bug#46165 strcoll()在Windows上不能与UTF-8字符串一起使用.如果您遇到同样的问题,您可以在错误报告页面上向PHP团队提供反馈(另外两个,可能是相关的,错误被归类为虚假 - 我不认为这个错误是假的 ;-).

感谢大家.

推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有