Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a shorter replacement for Kotlin's deprecated String.capitalize() function?

Kotlin deprecated the capitalize function on String class, and their suggested replacement is obnoxiously long. This is an example of a situation where they made the right call on deprecating it, but the wrong call on the user experience.

For example, this code:

val x = listOf("foo", "bar", "baz").map { it.capitalize() } 

is "cleaned up" by the IDE to become:

val x = listOf("foo", "bar", "baz").map { it.replaceFirstChar {                     if (it.isLowerCase()) it.titlecase(                         Locale.getDefault()                     ) else it.toString()                 } } 

This is preeeeetty ugly. What can we do about it?

like image 249
Stevey Avatar asked Jun 04 '21 21:06

Stevey


People also ask

What string method capitalizes all letters in a string?

The toUpperCase() method converts a string to uppercase letters. The toUpperCase() method does not change the original string.

How do you capitalize the first letter in Java?

The simplest way to capitalize the first letter of a string in Java is by using the String. substring() method: String str = "hello world!"; // capitalize first letter String output = str.

How to capitalize the first letter of a string in Kotlin?

In this example, we will take a string, and make the first letter of each word in this string as Uppercase using Kotlin For Loop and String.capitalize () method.

How do you replace a value in a string in Kotlin?

Kotlin – String Replace The basic String Replace method in Kotlin is String.replace (oldValue, newValue). ignoreCase is an optional argument, that could be sent as third argument to the replace () method.

How do I deprecate a method in Kotlin?

To do that in Kotlin, we can annotate the method with the @Deprecated annotation: The message property is always mandatory in the Deprecated annotation. Now if we use the old and now deprecated method, the Kotlin compiler will warn us about the deprecation:

What happens if ignorecase is false in Kotlin?

If false, character case would be considered while finding a match for oldValue in the String. The default value of ignoreCase is false. In the following Kotlin Example, we shall replace substring Programs with Examples value in the string, Kotlin Tutorial - Replace String - Programs.


2 Answers

A neat solution is to define a new extension function on String, which hides the gory details with a cleaner name:

/**  * Replacement for Kotlin's deprecated `capitalize()` function.  */ fun String.capitalized(): String {     return this.replaceFirstChar {          if (it.isLowerCase())             it.titlecase(Locale.getDefault())         else it.toString()      } } 

Now your old code can look like this:

val x = listOf("foo", "bar", "baz").map { it.capitalized() } 

You'll need to define the extension function at the top level in some package that you can import easily. For example, if you have a kotlin file called my.package.KotlinUtils (KotlinUtils.kt), and you put the definition inside it like so:

package my.package  fun String.capitalized(): String {...} 

Then you can import it in your other packages with:

import my.package.capitalized 
like image 22
Stevey Avatar answered Sep 19 '22 13:09

Stevey


The suggested replacement is ugly because it needs to be equivalent to the previous code:

  1. dependent on the default locale
  2. NOT converting an uppercase first char into titlecase (e.g. capitalize does NOT transform a leading 'DŽ' into 'Dž' - both are single characters here, try to select them)

If you didn't care too much about this behaviour, you can use a simpler expression using an invariant locale and unconditionally titlecasing the first character even if uppercase:

val x = listOf("foo", "bar", "baz").map { it.replaceFirstChar(Char::titlecase) } 

This means that if the first character is uppercase like 'DŽ', it will be transformed into the titlecase variant 'Dž' anyway, while the original code wouldn't touch it. This might actually be desirable.

One of the reasons capitalize() has been deprecated is because the behaviour of the method was unclear. For instance, behaviour #2 is pretty weird, and the behaviour of not capitalizing words in a sentence might be unexpected (C# would titlecase every space-separated word).

If you want to keep the exact current behaviour on purpose, but make it more convenient to use, you can always roll your own extension function with a name that suits you ("capitalize(d)" might not give enough info to the unaware reader):

fun String.titlecaseFirstCharIfItIsLowercase() = replaceFirstChar {      if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()  } 

Or for the version with invariant locale that titlecases the uppercase chars:

fun String.titlecaseFirstChar() = replaceFirstChar(Char::titlecase) 
like image 125
Joffrey Avatar answered Sep 18 '22 13:09

Joffrey