首页>Program>source

我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字符串语言环境的数组进行排序?

刚刚指出,这似乎是windows上的PHP问题,与 de_DE.utf8相同 用作语言环境在Linux机器上工作.但是,针对此windows特定问题的解决方案会很好...

最新回答
  • 2021-1-12
    1 #

    $a = array( 'Кръстев', 'Делян1', 'делян1', 'Делян2', 'делян3', 'кръстев' );
    $col = new \Collator('bg_BG');
    $col->asort( $a );
    var_dump( $a );
    

    print:

    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 intl扩展中定义.它随PHP 5.3源一起分发,但对于某些版本可能已禁用.例如.在Debian中,它位于php5-intl软件包中。

    Collator::compareusort有用 .

  • 2021-1-12
    2 #

    此问题的更新:

    尽管有关此问题的讨论表明我们可以用 strcoll()发现一个PHP错误 和/或 setlocale() ,事实显然并非如此.问题是 setlocale()的windows CRT实现的局限性 (PHPs setlocale() 只是围绕CRT调用的薄包装).以下是对MSDN页面" setlocale,_wsetlocale"的引用:

    The set of available languages, country/region codes, and code pages includes all those supported by the Win32 NLS API except code pages that require more than two bytes per character, such as UTF-7 and UTF-8. If you provide a code page like UTF-7 or UTF-8, setlocale will fail, returning NULL. 语言集和 国家/地区代码支持 setlocale在"语言"和" 国家/地区字符串。

    因此,当字符串是多字节编码时,不可能在windows上的PHP中使用可识别语言环境的字符串操作。

  • 2021-1-12
    3 #

    最终,如果不使用重新编码的字符串(UTF),就无法以简单的方式解决此问题. -8→windows-1252或ISO-8859-1),这是由THP所建议的,因为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上提交了一个错误报告:错误#46165 strcoll()在windows上不适用于UTF-8字符串.如果您遇到相同的问题,可以在错误报告页面上向PHP团队提供反馈(另外两个可能相关的错误被归类为伪造-我认为这不是 错误是伪造;-)。

    谢谢大家。

  • 2021-1-12
    4 #

    这是一个非常复杂的问题,因为UTF-8编码的数据可以包含任何Unicode字符(即,来自许多8位编码的字符,它们在不同的语言环境中进行整理的方式不同) )。

    也许如果您将UTF-8数据转换为Unicode(不熟悉PHP unicode函数,对不起),然后将其标准化为NFD或NFKD,然后对代码点进行排序,可能会提供一些对您有意义的排序规则(即 "Ä"之前的" A")。

    检查我提供的链接。

    编辑:由于您提到输入数据是清晰的(我假设它们都属于" windows-1252"代码页),因此您应该执行以下转换:UTF-8→Unicode→windows-1252, windows-1252编码的数据可以选择" CP1252"区域设置。

  • 2021-1-12
    5 #

    在windows开发机上,使用代码页为1252的示例在这里工作得很好。

    $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);
    

    ... snip ...

    这是PHP 5.2.6.顺便说一句


    上面的例子是 wrong ,它使用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Äpfel2147483647
     UngetümeBirnen 2147483647
     UngetümeApfel 2147483647
     UngetümeUngetiere 2147483647
     ÖsterreichUngetüme2147483647
     ÄpfelUngetiere 2147483647
     ÄpfelBirnen 2147483647
     ApfelÄpfel2147483647
     Ungetiere Birnen 2147483647

    我确实发现了一些错误报告,这些错误报告被标记为虚假... 您最好的选择是提交我认为的错误报告...

  • 如何区分手动滚动(通过鼠标滚轮/滚动条)和Javascript / jQuery滚动?
  • javascript:检查嵌套对象中是否存在对象成员