题
我currentyl不知道如何排阵列,其中包含UTF-8encoded strings in PHP.阵列来自LDAP server使通过排序的数据库(不会有问题)是没有解决方案。以下不起作用我的窗户发展机(虽然我认为这应该是至少一个可能的解决方案):
$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 on Windows问题,因为同样的片段 de_DE.utf8
作为区域工作上的一个Linux机。尽管如此解决方案的这个窗户-具体问题将是很好...
解决方案 3
最终,如果没有使用#932;ΖΖΖΖΖΕΕ&#9 ΤΖΙΟΥ由于Huppie发现了一个明显的PHP错误。 为了总结这个问题,我创建了以下代码片段,它清楚地表明问题是使用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<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 上提交了一份错误报告: Bug#46165 strcoll()不适用于Windows上的UTF-8字符串。如果您遇到同样的问题,可以在错误报告页面上向PHP团队提供反馈(另外两个,可能是相关的,错误被归类为 bogus - 我不认为这个bug是 bogus ; - )。
感谢你们所有人。
其他提示
$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国际机场的扩展.它分布与PHP5.3来源,但可能障碍为某些基础之上。E.g。Debian是在包php5-国际机场。
Collator::compare
是很有用的 usort
.
此问题的更新:
尽管围绕这个问题的讨论显示我们可以用 strcoll()
和/或 <代码> setlocale() ,显然不是这种情况。问题是 setlocale()<的Windows CRT实现的限制/ code>
(PHPs setlocale()
只是CRT调用的一个薄包装器)。以下是对 MSDN页面“setlocale,_wsetlocale”的引用:
可用语言集, 国家/地区代码和代码页 包括所有支持的人 Win32 NLS API 除了代码页 每个需要两个以上的字节 字符,例如UTF-7和UTF-8。如果 你提供像UTF-7或 UTF-8,setlocale将失败,返回 NULL。语言和语言集 支持的国家/地区代码 setlocale列于语言和 国家/地区字符串。
因此,当字符串是多字节编码时,不可能在Windows上的PHP中使用区域设置感知字符串操作。
这是一个非常复杂的问题,因为UTF-8编码的数据可以包含任何Unicode字符(即来自许多8位编码的字符,这些字符在不同的语言环境中进行不同的整理)。
也许如果您将UTF-8数据转换为Unicode(不熟悉PHP unicode函数,抱歉),然后将它们标准化为 NFD或NFKD 然后对代码点进行排序可能会给出一些对您有意义的整理(即“A”之前的“&#196;”)。
检查我提供的链接。
编辑:既然你提到你的输入数据是清楚的(我假设它们都属于“windows-1252”代码页),那么你应该进行以下转换:UTF-8&#8594; Unicode&#8594; Windows-1252,Windows-1252编码数据在其上进行排序,选择“CP1252”。区域设置。
使用代码页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
我确实找到了一些被标记为错误报告 bugs.php.net/bug.php?id=28527"rel =“nofollow noreferrer”>虚假 ...... 你最好的选择是提交错误报告,我想虽然......
我发现以下帮助函数将字符串的所有字母转换为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"
}
我遇到了与德语“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] =&gt; &#196; gypten结果 [1] =&gt;英格兰点击 [2] =&gt;法国点击 [3] =&gt; &#214; sterreich结果 [4] =&gt;瑞士结果 )
您的排序规则需要与字符集匹配。由于您的数据是UTF-8编码的,因此您应该使用UTF-8排序规则。它可以在不同的平台上以不同的名称命名,但一个好的猜测是 de_DE.utf8
。
在UNIX系统上,您可以使用命令
获取当前安装的语言环境列表locale -a