From bbc14381887b501faa4a4f744cf951700f0e8ccd Mon Sep 17 00:00:00 2001 From: Julian R Date: Wed, 20 Aug 2025 16:02:16 +0200 Subject: [PATCH] [stdlib] KT-80748 add ensurePrefix and ensureSuffix extension functions --- libraries/stdlib/src/kotlin/text/Strings.kt | 44 +++++++++++++++++++++ libraries/stdlib/test/text/StringTest.kt | 30 ++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/libraries/stdlib/src/kotlin/text/Strings.kt b/libraries/stdlib/src/kotlin/text/Strings.kt index 8fcf97ba3f3c3..dcd54ebd1c4aa 100644 --- a/libraries/stdlib/src/kotlin/text/Strings.kt +++ b/libraries/stdlib/src/kotlin/text/Strings.kt @@ -630,6 +630,28 @@ public fun String.removePrefix(prefix: CharSequence): String { return this } +/** + * If this char sequence does not start with the given [prefix], returns a new char sequence + * with the prefix added. Otherwise, returns a new char sequence with the same characters. + */ +public fun CharSequence.ensurePrefix(prefix: CharSequence): CharSequence { + if (!this.startsWith(prefix)) { + return prefix.toString() + this.toString() + } + return subSequence(0, length) +} + +/** + * If this string does not start with the given [prefix], returns a copy of this string + * with the prefix added. Otherwise, returns this string. + */ +public fun String.ensurePrefix(prefix: CharSequence): String { + if (!this.startsWith(prefix)) { + return prefix.toString() + this + } + return this +} + /** * If this char sequence ends with the given [suffix], returns a new char sequence * with the suffix removed. Otherwise, returns a new char sequence with the same characters. @@ -652,6 +674,28 @@ public fun String.removeSuffix(suffix: CharSequence): String { return this } +/** + * If the char sequence not ends with the given [suffix], returns a copy of this string + * with the suffix appended. Otherwise, returns a new char sequence with the same characters. + */ +public fun CharSequence.ensureSuffix(suffix: CharSequence): CharSequence { + if (!endsWith(suffix)) { + return this.toString() + suffix.toString() + } + return subSequence(0, length) +} + +/** + * If the string not ends with the given [suffix], returns a copy of this string + * with the suffix appended. Otherwise, returns this string. + */ +public fun String.ensureSuffix(suffix: CharSequence): String { + if (!endsWith(suffix)) { + return this + suffix.toString() + } + return this +} + /** * When this char sequence starts with the given [prefix] and ends with the given [suffix], * returns a new char sequence having both the given [prefix] and [suffix] removed. diff --git a/libraries/stdlib/test/text/StringTest.kt b/libraries/stdlib/test/text/StringTest.kt index 7d6c253b6ebc6..364b60b06032d 100644 --- a/libraries/stdlib/test/text/StringTest.kt +++ b/libraries/stdlib/test/text/StringTest.kt @@ -596,6 +596,18 @@ class StringTest { assertEquals("sample", "sample".removeSuffix("")) } + @Test fun ensureSuffix() = withOneCharSequenceArg("fix") { suffix -> + assertEquals("suffix", "suf".ensureSuffix(suffix), "Appends suffix") + assertEquals("suffix", "suffix".ensureSuffix(suffix)) + assertEquals("sample", "sample".ensureSuffix("")) + } + + @Test fun ensurePrefix() = withOneCharSequenceArg("suf") { prefix -> + assertEquals("suffix", "fix".ensurePrefix(prefix), "Appends prefix") + assertEquals("suffix", "suffix".ensurePrefix(prefix)) + assertEquals("sample", "sample".ensurePrefix("")) + } + @Test fun removeSurrounding() = withOneCharSequenceArg { arg1 -> val pre = arg1("<") val post = arg1(">") @@ -628,6 +640,24 @@ class StringTest { assertContentEquals("sample", "sample".removeSuffix("")) } + @Test fun ensurePrefixCharSequence() = withTwoCharSequenceArgs { arg1, arg2 -> + fun String.ensurePrefix(prefix: String) = arg1(this).ensurePrefix(arg2(prefix)) + val prefix = "suf" + + assertContentEquals("suffix", "fix".ensurePrefix(prefix), "Appends prefix") + assertContentEquals("suffix", "suffix".ensurePrefix(prefix)) + assertContentEquals("sample", "sample".ensurePrefix("")) + } + + @Test fun ensureSuffixCharSequence() = withTwoCharSequenceArgs { arg1, arg2 -> + fun String.ensureSuffix(suffix: String) = arg1(this).ensureSuffix(arg2(suffix)) + val suffix = "fix" + + assertContentEquals("suffix", "suf".ensureSuffix(suffix), "Appends suffix") + assertContentEquals("suffix", "suffix".ensureSuffix(suffix)) + assertContentEquals("sample", "sample".ensureSuffix("")) + } + @Test fun removeSurroundingCharSequence() = withTwoCharSequenceArgs { arg1, arg2 -> fun String.removeSurrounding(prefix: String, postfix: String) = arg1(this).removeSurrounding(arg2(prefix), arg2(postfix))