Why replace `capitalize` with a check for whether it is lowercase before `titlecase` is called?

6.6k views Asked by At

When using Kotlin 1.5, Android Studio warns that String.capitalize is deprecated.

The suggested replacement is:

myString.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() })

Why is the check for isLowerCase neccessary?

Why can't I just do this:

myString.replaceFirstChar { it.titlecase(Locale.getDefault()) })
1

There are 1 answers

2
awesoon On BEST ANSWER

A quote from the ticket:

Additionally, users may have varied expectations about the behavior of fun String.capitalize(): String, and the expectations do not always coincide with what we have implemented (see the KEEP discussion). The function titlecases the first char of the receiver String only if it is a lower case letter. For instance, the result of "DŽ".capitalize() is "DŽ", while "dž".capitalize() is "Dž". Given the different expectations, we would like to introduce replaceFirstChar function to let users code exactly what they want.

The replacements are verbose, but preserve the behavior as close as possible. The resulting code can be simplified further if a more simple behavior is desired, for example to String.replaceFirstChar { it.uppercaseChar() }.


Below is the original answer based on my thoughts. Please also check comment as there is a good note regarding :

I suppose this is because they wanted to replicate original behavior. Currently capitalize implemented as:

public fun String.capitalize(locale: Locale): String {
    if (isNotEmpty()) {
        val firstChar = this[0]
        if (firstChar.isLowerCase()) {
            return buildString {
                val titleChar = firstChar.titlecaseChar()
                if (titleChar != firstChar.uppercaseChar()) {
                    append(titleChar)
                } else {
                    append([email protected](0, 1).uppercase(locale))
                }
                append([email protected](1))
            }
        }
    }
    return this
}

Also, according to the note:

The title case of a character is usually the same as its upper case with several exceptions.

There are some corner cases:

fun check(x: String) {
    println(x.capitalize())
    println(x.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() })
    println(x.replaceFirstChar { it.titlecase() })
}

fun main() {
    check("dz")
    check("DZ")
}

Output (playground):

Dz
Dz
Dz
DZ
DZ
Dz