我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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top