我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在Windows上的问题,与同一片段de_DE.utf8
作为区域工作的Linux机器上。 然而这个Windows的具体问题的解决方案将是很好...
Answer 1:
$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-国际机场。
Collator::compare
是有用的usort
。
Answer 2:
更新对这个问题:
即使解决此问题的讨论表明,我们可以发现一个PHP错误strcoll()
和/或setlocale()
,这显然并非如此。 问题是相当Windows的CRT实现的限制setlocale()
(PHP的setlocale()
是就在CRT电话薄包装)。 下面是一个引用MSDN网页“的setlocale,_wsetlocale” :
该组可用的语言,国家/地区代码和代码的网页的包括除每个字符要求多于两个字节,例如UTF-7和UTF-8代码页由Win32 NLS API支持的所有那些。 如果你提供一个代码页像UTF-7或UTF-8的setlocale将失败,返回NULL。 使用setlocale支持的一套语言和国家/地区代码的列在语言和国家/地区字符串。
因此,它是不可能在Windows中使用PHP语言环境感知的字符串操作时,字符串多字节编码。
Answer 3:
最终,这个问题不能以简单的方式来解决,而无需使用由ΤΖΩΤΖΙΟΥ的建议重新编码字符串(UTF-8→Windows的1252或ISO-8859-1),由于通过Huppie发现了一个明显的错误PHP。 总结这个问题,我创建了下面的代码片段,清楚地表明,这个问题是与strcoll()函数使用65001 Windows的UTF-8代码页时。
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_ *编码和语言环境,必须再改)时,片段也适用。
我提交的bug报告bugs.php.net : 错误#46165与strcoll()不能在Windows UTF-8字符串的工作 。 如果您遇到了同样的问题,你可以给你的反馈,错误报告页面上的PHP团队(其他两个,可能是相关的,是伪造的错误进行了分类-我不认为这个bug是假 ;-)。
感谢大家。
Answer 4:
这是一个非常复杂的问题 ,因为UTF-8编码的数据可包含(从整理不同的方式在不同的区域设置许多8位编码即字符)任何Unicode字符。
或许,如果你转换您的UTF-8的数据转换成Unicode(不熟悉PHP的unicode功能,比较遗憾),然后归他们进入NFD或NFKD ,然后排序的代码点可能会给一些整理,将是有意义的,你(即“A”之前的“A”)。
检查我提供的链接。
编辑:既然你提到你的输入数据是明确的(我假设他们都属于“窗口1252”代码页),那么你应该做下面的转换:UTF-8→统一→Windows的1252,其上的Windows 1252编码后的数据做了某种选择“CP1252”的语言环境。
Answer 5:
使用具有代码页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);
...略...
这是用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
我发现一些bug报告已被标记为假的 ......你所拥有的最好的办法是在提交错误报告,我想虽然...
Answer 6:
我发现这个下面辅助函数的字符串的所有字母转换为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"
}
Answer 7:
我面临着与德国“Umlaute”同样的问题。 经过一番研究,这个工作对我来说:
$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);
结果:
排列
(
[0] =>埃及
[1] =>英国
[2] =>法国
[3] =>奥地利
[4] =>瑞士
)
Answer 8:
你整理需要匹配的字符集。 因为你的数据是UTF-8编码,您应该使用UTF-8排序规则。 它可以以不同的不同的平台上被命名,但良好的猜测是de_DE.utf8
。
在UNIX系统上,你可以用命令当前安装的语言环境列表
locale -a
文章来源: How to sort an array of UTF-8 strings?