首頁>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特定問题的解決方案会很好...

最新回復
  • 5月前
    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有用 .

  • 5月前
    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中使用可識別語言環境的字元串操作。

  • 5月前
    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团队提供反馈(另外两个可能相關的錯誤被归類為偽造-我认為這不是 錯誤是偽造;-)。

    谢谢大家。

  • 5月前
    4 #

    這是一个非常複雜的問题,因為UTF-8編碼的資料可以包含任何Unicode字元(即,来自许多8位編碼的字元,它们在不同的語言環境中进行整理的方式不同) )。

    也许如果您將UTF-8資料轉換為Unicode(不熟悉PHP unicode函式,對不起),然後將其標準化為NFD或NFKD,然後對代碼點进行排序,可能会提供一些對您有意義的排序規則(即 "Ä"之前的" A")。

    檢查我提供的鏈接。

    編輯:由於您提到輸入資料是清晰的(我假設它们都屬於" windows-1252"代碼頁),因此您應该執行以下轉換:UTF-8→Unicode→windows-1252, windows-1252編碼的資料可以選擇" CP1252"區域設置。

  • 5月前
    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:檢查巢狀物件中是否存在物件成員