From 33150a08098e4de1d75cb7ac550a8c669cce3540 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Sun, 7 Jun 2020 20:35:11 +0300 Subject: [PATCH] KT-38817 capitalize uses title case for the first char where available This unifies its behavior with new capitalize overload with Locale. Co-authored-by: Abduqodiri Qurbonzoda --- libraries/stdlib/common/src/kotlin/TextH.kt | 20 ++++++++++++++- .../stdlib/js/src/kotlin/text/stringsCode.kt | 13 ++++++---- .../stdlib/jvm/src/kotlin/text/StringsJVM.kt | 25 +++++++++++-------- .../stdlib/jvm/test/text/StringJVMTest.kt | 21 +++++++++++++++- 4 files changed, 62 insertions(+), 17 deletions(-) diff --git a/libraries/stdlib/common/src/kotlin/TextH.kt b/libraries/stdlib/common/src/kotlin/TextH.kt index 085c6d4fbab..c7d9b5a5146 100644 --- a/libraries/stdlib/common/src/kotlin/TextH.kt +++ b/libraries/stdlib/common/src/kotlin/TextH.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -208,8 +208,26 @@ public expect fun String.toUpperCase(): String * @sample samples.text.Strings.toLowerCase */ public expect fun String.toLowerCase(): String + +/** + * Returns a copy of this string having its first letter titlecased using the rules of the default locale, + * or the original string if it's empty or already starts with a title case letter. + * + * The title case of a character is usually the same as its upper case with several exceptions. + * The particular list of characters with the special title case form depends on the underlying platform. + * + * @sample samples.text.Strings.capitalize + */ public expect fun String.capitalize(): String + +/** + * Returns a copy of this string having its first letter lowercased using the rules of the default locale, + * or the original string if it's empty or already starts with a lower case letter. + * + * @sample samples.text.Strings.decapitalize + */ public expect fun String.decapitalize(): String + public expect fun CharSequence.repeat(n: Int): String diff --git a/libraries/stdlib/js/src/kotlin/text/stringsCode.kt b/libraries/stdlib/js/src/kotlin/text/stringsCode.kt index 95e43337b1a..94d90d9acd1 100644 --- a/libraries/stdlib/js/src/kotlin/text/stringsCode.kt +++ b/libraries/stdlib/js/src/kotlin/text/stringsCode.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -70,8 +70,11 @@ public actual fun CharSequence.regionMatches(thisOffset: Int, other: CharSequenc /** - * Returns a copy of this string having its first letter uppercased, or the original string, - * if it's empty or already starts with an upper case letter. + * Returns a copy of this string having its first letter titlecased using the rules of the default locale, + * or the original string if it's empty or already starts with a title case letter. + * + * The title case of a character is usually the same as its upper case with several exceptions. + * The particular list of characters with the special title case form depends on the underlying platform. * * @sample samples.text.Strings.capitalize */ @@ -80,8 +83,8 @@ public actual fun String.capitalize(): String { } /** - * Returns a copy of this string having its first letter lowercased, or the original string, - * if it's empty or already starts with a lower case letter. + * Returns a copy of this string having its first letter lowercased using the rules of the default locale, + * or the original string if it's empty or already starts with a lower case letter. * * @sample samples.text.Strings.decapitalize */ diff --git a/libraries/stdlib/jvm/src/kotlin/text/StringsJVM.kt b/libraries/stdlib/jvm/src/kotlin/text/StringsJVM.kt index 3ebab62a344..4433d997aa5 100644 --- a/libraries/stdlib/jvm/src/kotlin/text/StringsJVM.kt +++ b/libraries/stdlib/jvm/src/kotlin/text/StringsJVM.kt @@ -569,19 +569,24 @@ public inline fun String.toPattern(flags: Int = 0): java.util.regex.Pattern { } /** - * Returns a copy of this string having its first letter uppercased, or the original string, - * if it's empty or already starts with an upper case letter. + * Returns a copy of this string having its first letter titlecased using the rules of the default locale, + * or the original string if it's empty or already starts with a title case letter. + * + * The title case of a character is usually the same as its upper case with several exceptions. + * The particular list of characters with the special title case form depends on the underlying platform. * * @sample samples.text.Strings.capitalize */ public actual fun String.capitalize(): String { - return if (isNotEmpty() && this[0].isLowerCase()) substring(0, 1).toUpperCase() + substring(1) else this + return capitalize(Locale.getDefault()) } /** - * Returns a copy of this string having its first letter titlecased preferring [Char.toTitleCase] (if different from - * [Char.toUpperCase]) or by [String.toUpperCase] using the specified [locale], or the original string, - * if it's empty or already starts with an upper case letter. + * Returns a copy of this string having its first letter titlecased using the rules of the specified [locale], + * or the original string if it's empty or already starts with a title case letter. + * + * The title case of a character is usually the same as its upper case with several exceptions. + * The particular list of characters with the special title case form depends on the underlying platform. */ @SinceKotlin("1.4") @WasExperimental(ExperimentalStdlibApi::class) @@ -605,17 +610,17 @@ public fun String.capitalize(locale: Locale): String { } /** - * Returns a copy of this string having its first letter lowercased, or the original string, - * if it's empty or already starts with a lower case letter. + * Returns a copy of this string having its first letter lowercased using the rules of the default locale, + * or the original string if it's empty or already starts with a lower case letter. * * @sample samples.text.Strings.decapitalize */ public actual fun String.decapitalize(): String { - return if (isNotEmpty() && this[0].isUpperCase()) substring(0, 1).toLowerCase() + substring(1) else this + return if (isNotEmpty() && !this[0].isLowerCase()) substring(0, 1).toLowerCase() + substring(1) else this } /** - * Returns a copy of this string having its first letter lowercased using the specified [locale], + * Returns a copy of this string having its first letter lowercased using the rules of the specified [locale], * or the original string, if it's empty or already starts with a lower case letter. */ @SinceKotlin("1.4") diff --git a/libraries/stdlib/jvm/test/text/StringJVMTest.kt b/libraries/stdlib/jvm/test/text/StringJVMTest.kt index 84b6ea48d35..d2fc5aa6fb6 100644 --- a/libraries/stdlib/jvm/test/text/StringJVMTest.kt +++ b/libraries/stdlib/jvm/test/text/StringJVMTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -74,6 +74,25 @@ class StringJVMTest { assertEquals("UTF-32BE", Charsets.UTF_32BE.name()) } + @Test fun capitalize() { + // Case mapping that results in multiple characters (validating Character.toUpperCase was not used). + assertEquals("SSßß", "ßßß".capitalize()) + + // Case mapping where title case is different than uppercase and so Character.toTitleCase is preferred. + assertEquals("Dzdzdz", "dzdzdz".capitalize()) + assertEquals("DZDZDZ", "DZDZDZ".capitalize()) + } + + @Test fun decapitalize() { + assertEquals("aBC", "ABC".decapitalize()) + assertEquals("abc", "Abc".decapitalize()) + assertEquals("abc", "abc".decapitalize()) + + // Case mapping where title case is different than uppercase. + assertEquals("dzdzdz", "DZdzdz".decapitalize()) + assertEquals("dzdzdz", "Dzdzdz".decapitalize()) + } + @Test fun capitalizeLocale() { assertEquals("ABC", "ABC".capitalize(Locale.US)) assertEquals("Abc", "Abc".capitalize(Locale.US))