Я столкнулся с основной проблемой с Kotlin Android (API 29)
import kotlin.text.Charsets.UTF_8
var buf = byteArrayOf(0xF0.toByte(), 0xa9.toByte(), 0xbd.toByte(), 0xbe.toByte())
var s = String( buf, UTF_8)
Log.e(TAG, "buf len ${buf.size} as UTF-8 : <$s8> len ${s8.length}")
После преобразования строки из байтового буфера я получаю длину строки = 2 (как будто Котлин считает, что строка имеет формат UTF-16), но, конечно, длина строки должна быть равна 1. Нет проблем с Python!!
Выход:
buf len 4 as UTF-8 : <𩽾> len 2
Я а. он недоумевал: как это возможно? Как преобразование строк в Котлине может быть неправильным?
Обратите внимание, что UTF-8 F0A9BDBE соответствует символу 𩽾.
Это не явление Android или Kotlin, а базовая реализация Java String. Например, вы получите те же результаты в эквивалентной реализации Java, работающей на настольной JVM.
length() для строк Java определяется как «количество единиц кода Юникода в строке». (В своем вопросе вы упомянули Python: Java и Python просто различаются в этом отношении.)
«Кодовая единица Юникода», в свою очередь, определяется как «16-битные символьные значения, которые являются кодовыми единицами кодировки UTF-16».
Ваш персонаж 𩽾 представлен в UTF-16 с помощью двух суррогатов (D867 + DF7E), поэтому length() сообщает 2.
В конечном итоге вас может заинтересовать количество точек кода, которое более тесно коррелирует с количеством отображаемых символов. В String есть такие методы, как codePoints() и codePointCount(), которые могут здесь помочь. (Я не совсем уверен, сможете ли вы использовать API потоковой передачи, который codePoints() есть в вашем проекте Android.)
Вот пример, в котором я сделал расширение для String, чтобы избежать необходимости каждый раз иметь дело с индексами:
val buf = byteArrayOf(0xF0.toByte(), 0xa9.toByte(), 0xbd.toByte(), 0xbe.toByte())
val s = String(buf, UTF_8)
fun String.totalCodePointCount() = codePointCount(0, length)
s.totalCodePointCount() // returns 1
Эта запись в блоге представляет собой отличный обзор, который охватывает другие темы, такие как смайлики, которые мое предложение по подсчету кодовых точек не охватывает.