2015-06-02 18 views
6

Sto costruendo un'API per un'applicazione mobile e mi sembra di avere un problema nel conteggio della lunghezza di una stringa contenente emoji. Il mio codice:PHP - lunghezza della stringa che contiene emoji/caratteri speciali

$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))); 

la risposta di questo è:

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

però dovrei ottenere 17 come risultato. Abbiamo provato a fissare la lunghezza della stringa su iOS, Android e Windows Phone, sono 17 ovunque. Snippet iOS (rapido):

var str = "✌️ @mention" 
(str as NSString).length // 17 
count(str) // 13 
count(str.utf16) // 17 
count(str.utf8) // 27 

È necessario utilizzare NSString a causa di una libreria. Ho bisogno di questo per ottenere la posizione iniziale e finale di "@mention". Se la stringa contiene solo testo o solo emoji, funziona correttamente, quindi probabilmente c'è qualche problema con i contenuti misti.

Cosa sto sbagliando? Quali altre informazioni posso fornire a voi ragazzi per farmi nella giusta direzione?

Grazie!

+0

provare a utilizzare mb_substr, mb_str lunghezza può essere un'opzione –

risposta

12

Le tue funzioni stanno contando cose diverse.

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 

Le stringhe PHP sono in modo nativo.

strlen() conta il numero di byte in una stringa: 27.

mb_strlen(..., 'utf-8') conta il numero di punti di codice (caratteri Unicode) in una stringa quando suoi byte vengono decodificati per caratteri utilizzando la codifica UTF-8: 14.

(l'altro esempio conteggi sono molto senso come sono basati sul trattare la stringa di input come una codifica quando effettivamente contiene dati in una codifica differente.)

NSStrings sono nativamente contati come UTF-16 unità di codice . Ci sono 17, non 14, perché la stringa sopra contiene caratteri come che non si adattano a una singola unità di codice UTF-16, quindi devono essere codificati come una coppia di surrogati. Non ci sono funzioni che conteranno le stringhe in unità di codice UTF-16 in PHP, ma poiché ciascuna unità di codice è codificata a due byte, è possibile risolverla con sufficiente facilità codificando in UTF-16 e dividendo il numero di byte di due:

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

(Nota: il suffisso le è necessario fare iconv encode a un particolare endianness di UTF-16, e non inquinare il conteggio scegliendo uno e l'aggiunta di una distinta base per l'inizio della stringa da dire quale ha scelto.)

+0

GRANDE! grazie :) funziona! – gabo

+0

dice 14, ma solo 7 !! Il tuo metodo non sembra funzionare. – Sibidharan

+1

@ Sibidharan: cosa intendi con "il mio metodo"? Che tipo di conteggio hai usato e cosa ti aspettavi? Come da tabella sopra, '' è 7 punti codice Unicode, 14 unità codice UTF-16 o 29 byte UTF-8. – bobince

4

Ho incluso un'immagine per aiutare a illustrare la risposta che @bobince ha dato.

In sostanza, tutti i punti di codice della coppia non surrogata si trasformano in due byte in UTF-16 mentre tutti i punti di codice della coppia surrogata finiscono con quattro byte. Se dividiamo questo per due otteniamo il valore della lunghezza prevista equivalente.

P.S.Si prega di perdonare l'errore nell'immagine in cui si dice "punti di codice" e dovrebbe dire "unità di codice"

unicode breakdown

Problemi correlati