2010-11-20 8 views
2

Dies funktioniert nicht, es macht sie Kauderwelsch:Warum teilt preg_split von PHP den hebräischen Buchstaben "נ" in UTF-8 auf, wenn er auf " s" aufteilt?

$foo = 'נ'; 
$bar = mb_convert_encoding($foo, 'UTF-8', mb_detect_encoding($foo)); 
print_r(preg_split('/\s/', $bar)); 

Array ([0] => [1] =>)

Aber das funktioniert:

$foo = 'נ'; 
$bar = mb_convert_encoding($foo, 'ISO-8859-8', mb_detect_encoding($foo)); 
$baz = preg_split('/\s/', $bar); 
echo(mb_convert_encoding($baz[0], 'UTF-8', 'ISO-8859-8')); 

נ

Das Problem ist nur mit dem Buchstaben "נ". Es funktioniert gut mit allen anderen hebräischen Buchstaben. Gibt es dafür eine Lösung?

Antwort

7

Wenn mit UTF-8-Daten arbeiten, verwenden Sie immer die u modifier in Ihrem Muster:

/\s/u 

Denn sonst wird das Muster als UTF-8 nicht interpretiert. Wie in diesem Fall wird das Zeichen נ (U + 05E0) mit 0xD7A0 in UTF-8 codiert. Und steht für eine beliebige \s Leerzeichen (gemäß PCRE):

Die \s Zeichen HT sind (9), LF (10), FF (12), CR (13) und Raum (32).

Wenn UTF-8-Unterstützung hinzugefügt wurde, haben sie auch hinzugefügt eine spezielle Option genannt PCRE_UCP hat \b, \d, \s und \w nicht nur US-ASCII-Zeichen übereinstimmen, sondern auch andere Unicode-Zeichen durch ihre Unicode-Eigenschaften:

standardmäßig in UTF-8-Modus Zeichen mit Werten größer als 128 entsprechen nie \d, \s oder \w und immer \D übereinstimmen, \S und \W. [...] Wenn jedoch PCRE mit Unicode-Eigenschaft Unterstützung kompiliert wird, und die PCRE_UCP Option gesetzt ist, wird das Verhalten geändert, so dass Unicode-Eigenschaften verwendet werden Zeichentypen zu bestimmen, wie folgt:

  • \d jedes Zeichen, dass \p{Nd} matches (Dezimalziffer)
  • \s jedes Zeichen, das \p{Z} Einstimmungen sowie HT, LF, FF, CR
  • \w jedes Zeichen, das \p{L} oder \p{N} Einstimmungen sowie unterstreichen

Und das nicht schließende Leerzeichen U + 00A0 hat die Eigenschaft eines Separators (\p{Z}).

Und obwohl Ihr Muster ist nicht in UTF-8-Modus, so scheint es, dass \stut Spiel, dass 0xA0 im UTF-8-Codewort 0xD7A0, an dieser Stelle die Zeichenfolge aufgeteilt und ein Feld zurückgibt, die array("\xD7", "") entsprechen .

Und das ist offensichtlich ein Fehler, wie das Muster nicht in UTF-8-Modus ist aber 0xA0 ist größer als 0x80 (zusätzlich würde 0xA0 als 0xC2A0 codiert werden). Die bug #52971 PCRE-Meta-Characters not working with utf-8 könnte damit verwandt sein.

+0

es funktioniert! Danke! – happytoad

+0

@happytoad: Ich habe einige mögliche Erklärungen für dieses spezifische Verhalten hinzugefügt. – Gumbo

+0

Leute, die an der Beziehung zwischen Unicode-Zeichen und Unicode-Eigenschaften interessiert sind, einschließlich Dinge wie '\ s' und' \ v' (vertikaler Raum) und '\ h' (horizontaler Raum) sollten meine zwei grundlegenden Dienstprogramme greifen, [ * Unichars *] (http://training.perl.com/scripts/unichars) und [* uniprops *] (http://training.perl.com/scripts/uniprops). Anweisungen und Beispiele sind enthalten. Es gibt auch ein drittes verwandtes Programm, [* uninames *] (http://training.perl.com/scripts/uninames), das Ihnen vielleicht auch gefällt. – tchrist