문제

i curtyl은 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 Locale은 Linux 시스템에서 작동합니다. 그럼에도 불구 하고이 Windows 특정 문제에 대한 해결책은 좋을 것입니다 ...

도움이 되었습니까?

해결책 3

결국이 문제는 Huppie에 의해 발견 된 명백한 PHP 버그로 인해 τζωτζιου에 의해 제안 된 바와 같이, 재구성 된 문자열 (UTF-8 → Windows-1252 또는 ISO-8859-1)을 사용하지 않고는 간단한 방식으로 해결할 수 없습니다. 문제를 요약하기 위해 65001 Windows-UTF-8-CodePage를 사용할 때 문제가 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 팀에 피드백을 제공 할 수 있습니다 (아마도 다른 두 가지 관련, 버그는 가짜 - 나는이 버그가 있다고 생각하지 않습니다 가짜 ;-).

여러분 모두에게 감사합니다.

다른 팁

$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 INTL 확장. PHP 5.3 소스로 배포되지만 일부 빌드의 경우 비활성화 될 수 있습니다. 예를 들어 데비안에서는 Php5-Intl 패키지에 있습니다.

Collator::compare 유용합니다 usort.

이 문제에 대한 업데이트 :

이 문제에 대한 논의가 우리가 PHP 버그를 발견 할 수 있음을 밝혀 냈음에도 불구하고 strcoll() 및/또는 setlocale(), 이것은 분명히 사실이 아닙니다. 문제는 오히려 Windows CRT 구현의 한계입니다. setlocale() (Phps setlocale() CRT 호출 주변의 얇은 포장지입니다). 다음은 인용입니다 MSDN 페이지 "SetLocale, _wsetLocale":

사용 가능한 언어, 국가/지역 코드 및 코드 페이지 세트에는 Win32 NLS API가 지원하는 모든 언어가 포함됩니다. UTF-7 및 UTF-8과 같은 문자 당 2 바이트 이상이 필요한 코드 페이지를 제외하고. UTF-7 또는 UTF-8과 같은 코드 페이지를 제공하면 SetLocale이 실패하여 NULL을 반환합니다. SetLocale에서 지원하는 언어 및 국가/지역 코드 세트는 언어 및 국가/지역 문자열로 나열되어 있습니다.

따라서 문자열이 멀티 바이트 인코딩 된 경우 Windows에서 PHP 내에서 Locale-Aware 문자열 작업을 사용하는 것은 불가능합니다.

이것은 매우 복잡합니다 문제, UTF-8 인코딩 된 데이터에는 모든 유니 코드 문자 (즉, 다른 로케일에서 다르게 수집되는 많은 8 비트 인코딩의 문자)를 포함 할 수 있기 때문입니다.

아마도 UTF-8 데이터를 유니 코드로 변환 한 경우 (PHP 유니 코드 함수에 익숙하지 않음) 정규화 된 경우 NFD 또는 NFKD 그리고 코드 포인트를 정렬하면 당신에게 의미가있는 일부 콜레이션을 제공 할 수 있습니다 (예 : "a"이전 "ä").

내가 제공 한 링크를 확인하십시오.

편집 : 입력 데이터가 명확하다고 언급하기 때문에 (모두 "Windows-1252"CodePage에 속한다고 가정하면 UTF-8 → Unicode → Windows-1252는 Windows-1252에서 다음과 같은 변환을 수행해야합니다. 인코딩 된 데이터는 "CP1252"로케일을 선택하는 정렬을 수행합니다.

CodePage 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과 관련이있었습니다. BTW.


위의 예는입니다 잘못된, UTF-8 대신 ASCII 인코딩을 사용합니다. 나는 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

나는 일부를 찾았다 버그 보고서 신고 된 존재 가짜... 당신이 가진 가장 좋은 방법은 내가 생각하는 버그 보고서를 제출하는 것입니다 ...

다음과 같은 도우미 기능을 찾았습니다 문자열의 모든 문자를 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] => ägypten
1] => 영국
2] => 프랑스
3] => Österreich
4] => Schweiz
)

Collation은 캐릭터 세트와 일치해야합니다. 데이터가 UTF-8 인코딩되므로 UTF-8 Collation을 사용해야합니다. 그것은 다른 플랫폼에서 다르게 명명 될 수 있지만 좋은 추측은 de_DE.utf8.

UNIX 시스템에서는 명령과 함께 현재 설치된 로케일 목록을 얻을 수 있습니다.

locale -a
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top