Sortieren eines UTF-8 kodierten Arrays nach seinen Werten

Die PHP Funktion asort kann auch mit UTF-8 Werten genutzt werden. Voraussetzung ist allerdings, dass in einem Array mit Textwerten, das richtige locale gesetzt ist. Zudem muss die Konstante SORT_LOCALE_STRING bei asort benutzt werden. Nun tritt dennoch ein Problem auf: Wenn die Textwerte UTF-8 kodiert sind, werden die Ergebnisse trotzdem single-byte sortiert, also z.B. ‘Ä’ aber auch ‘Ö’ kommen gleich nach dem ‘A’ weil diese Zeichen in UTF-8 mit zwei Zeichen kodiert sind wobei ‘Ã’ das erste davon ist. Um dies zu lösen sind zwei Wege möglich:

1. Weg: Locale mit Charset setzten

setlocale(LC_COLLATE, 'de_DE.UTF8', 'de.UTF8', 'DEU.UTF8', 'German_Germany.UTF8', 'German.UTF8'
    'de_DE.UTF-8', 'de.UTF-8', 'DEU.UTF-8', 'German_Germany.UTF-8', 'German.UTF-8');

Diese Methode ist systemabhängig und birgt ein gewisses Risiko, da in manchen Systemen die Locale nicht richtig gesetzt sind. Windows (als Server) unterstützt z.B. UTF-8 als Zeichenkodierung meist nicht (Windows benutzt WinCP, z.B. 1252).

2. Weg: Klasse ”Collate” benutzten

$coll = collator_create('de_DE');

Diese Lösung ist erst ab PHP 5.3.0 möglich und erfordert, dass die PHP-Extension php_intl installiert ist. Dies kann dann wie folgt geschehen:

$oldLocale = setlocale(LC_COLLATE, '0');

if (preg_match('/\.utf-?8\b/i', $oldLocale)) {
    # Alles richtig gesetzt
    asort($arrayToSort, SORT_LOCALE_STRING);
}
elseif (version_compare(PHP_VERSION, '5.3.0') < 1 && function_exists('collator_create')) {
    # Wir benutzten die Collator Klasse
    $coll = collator_create($oldLocale);
    collator_asort($coll, $arrayToSort, Collator::SORT_STRING);
}
else {
    # Wir versuchen locale mit Zeichenkodierung setzten
    $lang = preg_replace('/(?:\.|\@).*$/', '', $oldLocale);
    foreach (array('.UTF-8', '.utf-8', '.UTF8', '.utf8', '') as $enc)
        $locale[] = $lang . $enc;
    $newLocale = setlocale(LC_COLLATE, $locale);
    if (preg_match('/\.utf-?8\b/i', $newLocale)) {
        asort($arrayToSort, SORT_LOCALE_STRING);
        setlocale(LC_COLLATE, $oldLocale);
    }
    else {
        // An diesem Systerm funktioniert es nicht :(
        // Es bleibt nichts Anderes übrig als User-function zu schreiben
        // und 'usort'/'uasort' zu benutzen
    }
}

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s