我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的问题的解决方案会很好......
$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
.
有关此问题的更新:
尽管围绕这个问题的讨论显示我们可能已经发现了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中使用区域设置感知字符串操作.
最终,由于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团队提供反馈(另外两个,可能是相关的,错误被归类为虚假 - 我不认为这个错误是假的 ;-).
感谢大家.