Map String with Emojis to Array<String|Char>

Viewed 496

I want to convert my String to Array or List of Strings or Chars like: Array<String> or Array<Char>.

Example:

val myText = "Ab+2#✅'ü{" // Parse and print to Log

Should:

[ "A", "b", "", "+", "", "2", "", "#", "✅", "'", "", "ü", "", "{" ] // Array contains Strings or Chars

Java/ Kotlin method what doesn't work because of Emojis on Android:

myText.toList() // ❌ Fails because of Emojis
myText.toMutableList() // ❌ Fails because of Emojis
2 Answers

In Kotlin, if targeting JDK 8 or later you can use:

fun String.splitToCodePoints(): List<String> {
    return codePoints()
        .toList()
        .map { String(Character.toChars(it)) }
}

If using JDK 7, it's more manual:

fun String.splitToCodePoints(): List<String> {
    val list = mutableListOf<String>()
    var count = 0
    while (count < length) {
        with (codePointAt(count)){
            list.add(String(Character.toChars(this)))
            count += Character.charCount(this)
        }
    }
    return list
}

It seems the Kotlin standard library is lacking in these areas since you have to rely on JDK boxed primitive classes to convert the code points integers to Strings.

As mentioned in another answer here, this will have to be more involved if you need to handle the zero width joiner. You might need to remove any zero width joiners so the characters can be shown separately, or you might want to display them together and so need to manipulate the list to combine elements separated by joiners. If the language uses ligatures, this would affect this decision.

In Java, you can get a stream of the string's code points, and convert each of them back into a string:

var myText = "Ab+2#✅'ü{";
String[] array = myText.codePoints()
    .boxed()
    .map(i -> new String(Character.toChars(i)))
    .toArray(String[]::new)

Returns:

{ "A", "b", "", "+", "", "2", "", "", "#", "✅", "'", "", "ü", "", "", "{" }

Note that some emojis, like flags or skin color and gender variations, are composed by joining multiple Unicode code points so this may or may not produce the result you want.

Related