2015-06-02 23 views
6

Ich baue eine API für eine mobile Anwendung und ich habe ein Problem mit dem Zählen der Länge einer Zeichenfolge mit Emojis. Mein Code:PHP - Länge der Zeichenfolge mit Emojis/spezielle Zeichen

$str = "✌️ @mention"; 

printf("strlen: %d" . PHP_EOL, strlen($str)); 
printf("mb_strlen UTF-8: %d" . PHP_EOL, mb_strlen($str, "UTF-8")); 
printf("mb_strlen UTF-16: %d" . PHP_EOL, mb_strlen($str, "UTF-16")); 
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("UTF-8", "UTF-16", $str))); 
printf("iconv UTF-16: %d" . PHP_EOL, iconv_strlen(iconv("ISO-8859-1", "UTF-16", $str))); 

die Antwort hierfür ist:

strlen: 27 
mb_strlen UTF-8: 14 
mb_strlen UTF-16: 13 
iconv UTF-16: 14 
iconv UTF-16: 27 

aber ich 17 als Ergebnis erhalten sollte. Wir haben versucht, die String-Länge auf iOS, Android und Windows Phone, es ist 17 überall. iOS (Swift) -Snippet:

Wir müssen den NSString wegen einer Bibliothek verwenden. Ich brauche das, um die Start- und Endposition der "@mention" zu erhalten. Wenn die Zeichenfolge nur Text oder nur Emojis enthält, funktioniert es gut, wahrscheinlich gibt es ein Problem mit gemischten Inhalten.

Was mache ich falsch? Welche anderen Informationen kann ich Ihnen geben, um mich in die richtige Richtung zu bringen?

Danke!

+0

versuchen mb_substr verwenden, können mb_str Länge eine Option sein –

Antwort

12

Ihre Funktionen zählen alle verschiedene Dinge.

Graphemes:          ✌    ️      @  m  e  n  t  i  o  n 13 
         ----------- ----------- -------- --------------------- ------ ------ ------ ------ ------ ------ ------ ------ ------ 
Code points:   U+1F44D  U+1F3FF  U+270C  U+1F3FF  U+FE0F U+0020 U+0040 U+006D U+0065 U+006E U+0074 U+0069 U+006F U+006E 14 
UTF-16 code units:  D83D DC4D D83C DFFF  270C  D83C DFFF  FE0F  0020 0040 006D 0065 006E 0074 0069 006F 006E 17 
UTF-16-encoded bytes: 3D D8 4D DC 3C D8 FF DF 0C 27 3C D8 FF DF 0F FE 20 00 40 00 6D 00 65 00 6E 00 74 00 69 00 6F 00 6E 00 34 
UTF-8-encoded bytes: F0 9F 91 8D F0 9F 8F BF E2 9C 8C F0 9F 8F BF EF B8 8F 20  40  6D  65  6E  74  69  6F  6E 27 

PHP-Strings sind native Bytes.

strlen() zählt die Anzahl der Bytes in einem String: 27.

mb_strlen(..., 'utf-8') zählt die Anzahl der Codepunkte (Unicode-Zeichen) in einer Zeichenfolge, wenn seine Bytes Zeichen decodiert werden unter Verwendung der UTF-8-Kodierung: 14.

(das andere Beispiel zählt, sind weitgehend bedeutungslos, da sie auf die Behandlung der Eingabezeichenfolge als eine Codierung basiert sind, wenn es Daten enthält tatsächlich in einer anderen Codierung.)

NSStrings werden als UTF-16-Codeeinheiten nativ gezählt . Es gibt 17, nicht 14, weil die obige Zeichenfolge Zeichen wie enthält, die nicht in eine einzelne UTF-16-Codeeinheit passen, daher müssen sie als Ersatzpaar codiert werden. Es gibt keine Funktionen, die Strings in UTF-16-Code-Einheiten in PHP zählen, aber weil jede Code-Einheit in zwei Bytes kodiert ist, können Sie es einfach genug durch die Kodierung nach UTF-16 und dividieren Sie die Anzahl der Bytes durch zwei:

strlen(iconv('utf-8', 'utf-16le', $str))/2 

(Hinweis: der le Suffix iconv kodieren auf eine bestimmte endianness von UTF-16, und nicht versaut die Zählung zu machen eine durch die Wahl und das Hinzufügen einer Stückliste zu Beginn der Zeichenfolge notwendig ist, Sagen Sie, welchen es ausgewählt hat.)

+0

GREAT! Danke :) es funktioniert! – gabo

+0

sagt 14, aber nur 7 !! Ihre Methode scheint nicht zu funktionieren. – Sibidharan

+1

@ Sibidharan: was meinst du, "meine Methode"? Welche Form des Zählens hast du benutzt und was hast du erwartet? Wie in der obigen Tabelle angegeben, sind 7 Unicode-Codepunkte, 14 UTF-16-Codeeinheiten oder 29 UTF-8-Bytes. – bobince

4

Ich habe ein Bild eingefügt, um die Antwort zu verdeutlichen, die @bobince gab.

Im Wesentlichen enden alle Nicht-Ersatzpaar-Codepunkte als zwei Bytes in UTF-16, während alle Ersatzpaar-Codepunkte als vier Bytes enden. Wenn wir dies durch zwei teilen, erhalten wir den äquivalenten erwarteten Längenwert.

P.S.Bitte geben Sie die Fehler im Bild vergeben, wo es „Code-Punkte“, sagt und sollte „Code-Einheiten“, sagen

unicode breakdown