From 47560d3db1320bfd4a22dfc06fc6f3cdd8cb9135 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 14 Oct 2015 00:48:48 +0300 Subject: [PATCH] Add hidden declarations for replaced overloads with String receiver in hand-written code. --- libraries/stdlib/src/kotlin/text/Strings.kt | 5 - .../src/kotlin/text/StringsDeprecated.kt | 868 ++++++++++++++++++ .../src/kotlin/text/StringsDeprecatedJVM.kt | 446 +++++++++ 3 files changed, 1314 insertions(+), 5 deletions(-) create mode 100644 libraries/stdlib/src/kotlin/text/StringsDeprecated.kt create mode 100644 libraries/stdlib/src/kotlin/text/StringsDeprecatedJVM.kt diff --git a/libraries/stdlib/src/kotlin/text/Strings.kt b/libraries/stdlib/src/kotlin/text/Strings.kt index ae71342df17..329c8b203b5 100644 --- a/libraries/stdlib/src/kotlin/text/Strings.kt +++ b/libraries/stdlib/src/kotlin/text/Strings.kt @@ -131,11 +131,6 @@ public fun CharSequence.padEnd(length: Int, padChar: Char = ' '): String { return sb.toString() } -/** Returns `true` if the string is not `null` and not empty */ -@Deprecated("Use !isNullOrEmpty() or isNullOrEmpty().not() for nullable strings.", ReplaceWith("this != null && this.isNotEmpty()")) -@kotlin.jvm.JvmName("isNotEmptyNullable") -public fun CharSequence?.isNotEmpty(): Boolean = this != null && this.length() > 0 - /** * Returns `true` if this nullable string is either `null` or empty. */ diff --git a/libraries/stdlib/src/kotlin/text/StringsDeprecated.kt b/libraries/stdlib/src/kotlin/text/StringsDeprecated.kt new file mode 100644 index 00000000000..f6b89ed495b --- /dev/null +++ b/libraries/stdlib/src/kotlin/text/StringsDeprecated.kt @@ -0,0 +1,868 @@ +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("StringsKt") + + +package kotlin + +import java.util.NoSuchElementException +import kotlin.text.MatchResult +import kotlin.text.Regex + +/** + * Returns the string with leading and trailing characters matching the [predicate] trimmed. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +inline public fun String.trim(predicate: (Char) -> Boolean): String { + var startIndex = 0 + var endIndex = length() - 1 + var startFound = false + + while (startIndex <= endIndex) { + val index = if (!startFound) startIndex else endIndex + val match = predicate(this[index]) + + if (!startFound) { + if (!match) + startFound = true + else + startIndex += 1 + } + else { + if (!match) + break + else + endIndex -= 1 + } + } + + return substring(startIndex, endIndex + 1) +} + +/** + * Returns the string with leading characters matching the [predicate] trimmed. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +inline public fun String.trimStart(predicate: (Char) -> Boolean): String { + for (index in this.indices) + if (!predicate(this[index])) + return substring(index) + + return "" +} + +/** + * Returns the string with trailing characters matching the [predicate] trimmed. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +inline public fun String.trimEnd(predicate: (Char) -> Boolean): String { + for (index in this.indices.reversed()) + if (!predicate(this[index])) + return substring(0, index + 1) + + return "" +} + +/** + * Returns the string with leading and trailing characters in the [chars] array trimmed. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.trim(vararg chars: Char): String = trim { it in chars } + +/** + * Returns the string with leading and trailing characters in the [chars] array trimmed. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.trimStart(vararg chars: Char): String = trimStart { it in chars } + +/** + * Returns the string with trailing characters in the [chars] array trimmed. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.trimEnd(vararg chars: Char): String = trimEnd { it in chars } + +/** + * Returns a string with leading and trailing whitespace trimmed. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.trim(): String = trim { it.isWhitespace() } + +/** + * Returns a string with leading whitespace removed. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.trimStart(): String = trimStart { it.isWhitespace() } + +/** + * Returns a string with trailing whitespace removed. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.trimEnd(): String = trimEnd { it.isWhitespace() } + +/** + * Left pad a String with a specified character or space. + * + * @param length the desired string length. + * @param padChar the character to pad string with, if it has length less than the [length] specified. Space is used by default. + * @returns Returns a string, of length at least [length], consisting of string prepended with [padChar] as many times. + * as are necessary to reach that length. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.padStart(length: Int, padChar: Char = ' '): String { + if (length < 0) + throw IllegalArgumentException("String length $length is less than zero.") + if (length <= this.length()) + return this + + val sb = StringBuilder(length) + for (i in 1..(length - this.length())) + sb.append(padChar) + sb.append(this) + return sb.toString() +} + +/** + * Right pad a String with a specified character or space. + * + * @param length the desired string length. + * @param padChar the character to pad string with, if it has length less than the [length] specified. Space is used by default. + * @returns Returns a string, of length at least [length], consisting of string prepended with [padChar] as many times. + * as are necessary to reach that length. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.padEnd(length: Int, padChar: Char = ' '): String { + if (length < 0) + throw IllegalArgumentException("String length $length is less than zero.") + if (length <= this.length()) + return this + + val sb = StringBuilder(length) + sb.append(this) + for (i in 1..(length - this.length())) + sb.append(padChar) + return sb.toString() +} + +/** Returns `true` if the string is not `null` and not empty */ +@Deprecated("Use !isNullOrEmpty() or isNullOrEmpty().not() for nullable strings.", ReplaceWith("this != null && this.isNotEmpty()"), DeprecationLevel.ERROR) +@kotlin.jvm.JvmName("isNotEmptyNullable") +public fun CharSequence?.isNotEmpty(): Boolean = this != null && this.length() > 0 + + +/** Returns `true` if the string is not `null` and not empty */ +@Deprecated("Use !isNullOrEmpty() or isNullOrEmpty().not() for nullable strings.", ReplaceWith("this != null && this.isNotEmpty()"), DeprecationLevel.HIDDEN) +@kotlin.jvm.JvmName("isNotEmptyNullable") +public fun String?.isNotEmpty(): Boolean = this != null && this.length() > 0 + +/** + * Returns `true` if this nullable string is either `null` or empty. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String?.isNullOrEmpty(): Boolean = this == null || this.length() == 0 + +/** + * Returns `true` if this string is empty (contains no characters). + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.isEmpty(): Boolean = length() == 0 + +/** + * Returns `true` if this string is not empty. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.isNotEmpty(): Boolean = length() > 0 + +// implemented differently in JVM and JS +//public fun String.isBlank(): Boolean = length() == 0 || all { it.isWhitespace() } + + +/** + * Returns `true` if this string is not empty and contains some characters except of whitespace characters. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.isNotBlank(): Boolean = !isBlank() + +/** + * Returns `true` if this nullable string is either `null` or empty or consists solely of whitespace characters. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String?.isNullOrBlank(): Boolean = this == null || this.isBlank() + +/** + * Returns the range of valid character indices for this string. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public val String.indices: IntRange + get() = 0..length() - 1 + +/** + * Returns the index of the last character in the String or -1 if the String is empty. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public val String.lastIndex: Int + get() = this.length() - 1 + +/* +/** + * Returns a substring before the first occurrence of [delimiter]. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.substringBefore(delimiter: Char, missingDelimiterValue: String = this): String { + val index = indexOf(delimiter) + return if (index == -1) missingDelimiterValue else substring(0, index) +} + +/** + * Returns a substring before the first occurrence of [delimiter]. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.substringBefore(delimiter: String, missingDelimiterValue: String = this): String { + val index = indexOf(delimiter) + return if (index == -1) missingDelimiterValue else substring(0, index) +} + +/** + * Returns a substring after the first occurrence of [delimiter]. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.substringAfter(delimiter: Char, missingDelimiterValue: String = this): String { + val index = indexOf(delimiter) + return if (index == -1) missingDelimiterValue else substring(index + 1, length()) +} + +/** + * Returns a substring after the first occurrence of [delimiter]. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.substringAfter(delimiter: String, missingDelimiterValue: String = this): String { + val index = indexOf(delimiter) + return if (index == -1) missingDelimiterValue else substring(index + delimiter.length(), length()) +} + +/** + * Returns a substring before the last occurrence of [delimiter]. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.substringBeforeLast(delimiter: Char, missingDelimiterValue: String = this): String { + val index = lastIndexOf(delimiter) + return if (index == -1) missingDelimiterValue else substring(0, index) +} + +/** + * Returns a substring before the last occurrence of [delimiter]. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.substringBeforeLast(delimiter: String, missingDelimiterValue: String = this): String { + val index = lastIndexOf(delimiter) + return if (index == -1) missingDelimiterValue else substring(0, index) +} + +/** + * Returns a substring after the last occurrence of [delimiter]. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.substringAfterLast(delimiter: Char, missingDelimiterValue: String = this): String { + val index = lastIndexOf(delimiter) + return if (index == -1) missingDelimiterValue else substring(index + 1, length()) +} + +/** + * Returns a substring after the last occurrence of [delimiter]. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.substringAfterLast(delimiter: String, missingDelimiterValue: String = this): String { + val index = lastIndexOf(delimiter) + return if (index == -1) missingDelimiterValue else substring(index + delimiter.length(), length()) +} +*/ + +/** + * Replaces the part of the string at the given range with the [replacement] string. + * @param firstIndex the index of the first character to be replaced. + * @param lastIndex the index of the first character after the replacement to keep in the string. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.replaceRange(firstIndex: Int, lastIndex: Int, replacement: String): String { + if (lastIndex < firstIndex) + throw IndexOutOfBoundsException("Last index ($lastIndex) is less than first index ($firstIndex)") + val sb = StringBuilder() + sb.append(this, 0, firstIndex) + sb.append(replacement) + sb.append(this, lastIndex, length()) + return sb.toString() +} + +/** + * Replace the part of string at the given [range] with the [replacement] string. + * + * The end index of the [range] is included in the part to be replaced. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.replaceRange(range: IntRange, replacement: String): String = replaceRange(range.start, range.end + 1, replacement) + +/** + * Removes the part of a string at a given range. + * @param firstIndex the index of the first character to be removed. + * @param lastIndex the index of the first character after the removed part to keep in the string. + * + * [lastIndex] is not included in the removed part. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.removeRange(firstIndex: Int, lastIndex: Int): String { + if (lastIndex < firstIndex) + throw IndexOutOfBoundsException("Last index ($lastIndex) is less than first index ($firstIndex)") + + if (lastIndex == firstIndex) + return this + + val sb = StringBuilder(length() - (lastIndex - firstIndex)) + sb.append(this, 0, firstIndex) + sb.append(this, lastIndex, length()) + return sb.toString() +} + +/** + * Removes the part of a string at the given [range]. + * + * The end index of the [range] is included in the removed part. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.removeRange(range: IntRange): String = removeRange(range.start, range.end + 1) + +/* +/** + * If this string starts with the given [prefix], returns a copy of this string + * with the prefix removed. Otherwise, returns this string. + */ +public fun String.removePrefix(prefix: String): String { + if (startsWith(prefix)) { + return substring(prefix.length()) + } + return this +} + +/** + * If this string ends with the given [suffix], returns a copy of this string + * with the suffix removed. Otherwise, returns this string. + */ +public fun String.removeSuffix(suffix: String): String { + if (endsWith(suffix)) { + return substring(0, length() - suffix.length()) + } + return this +} + +/** + * Removes from a string both the given [prefix] and [suffix] if and only if + * it starts with the [prefix] and ends with the [suffix]. + * Otherwise returns this string unchanged. + */ +public fun String.removeSurrounding(prefix: String, suffix: String): String { + if (startsWith(prefix) && endsWith(suffix)) { + return substring(prefix.length(), length() - suffix.length()) + } + return this +} + +/** + * Removes the given [delimiter] string from both the start and the end of this string + * if and only if it starts with and ends with the [delimiter]. + * Otherwise returns this string unchanged. + */ +public fun String.removeSurrounding(delimiter: String): String = removeSurrounding(delimiter, delimiter) + +/** + * Replace part of string before the first occurrence of given delimiter with the [replacement] string. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.replaceBefore(delimiter: Char, replacement: String, missingDelimiterValue: String = this): String { + val index = indexOf(delimiter) + return if (index == -1) missingDelimiterValue else replaceRange(0, index, replacement) +} + +/** + * Replace part of string before the first occurrence of given delimiter with the [replacement] string. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.replaceBefore(delimiter: String, replacement: String, missingDelimiterValue: String = this): String { + val index = indexOf(delimiter) + return if (index == -1) missingDelimiterValue else replaceRange(0, index, replacement) +} + +/** + * Replace part of string after the first occurrence of given delimiter with the [replacement] string. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.replaceAfter(delimiter: Char, replacement: String, missingDelimiterValue: String = this): String { + val index = indexOf(delimiter) + return if (index == -1) missingDelimiterValue else replaceRange(index + 1, length(), replacement) +} + +/** + * Replace part of string after the first occurrence of given delimiter with the [replacement] string. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.replaceAfter(delimiter: String, replacement: String, missingDelimiterValue: String = this): String { + val index = indexOf(delimiter) + return if (index == -1) missingDelimiterValue else replaceRange(index + delimiter.length(), length(), replacement) +} + +/** + * Replace part of string after the last occurrence of given delimiter with the [replacement] string. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.replaceAfterLast(delimiter: String, replacement: String, missingDelimiterValue: String = this): String { + val index = lastIndexOf(delimiter) + return if (index == -1) missingDelimiterValue else replaceRange(index + delimiter.length(), length(), replacement) +} + +/** + * Replace part of string after the last occurrence of given delimiter with the [replacement] string. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.replaceAfterLast(delimiter: Char, replacement: String, missingDelimiterValue: String = this): String { + val index = lastIndexOf(delimiter) + return if (index == -1) missingDelimiterValue else replaceRange(index + 1, length(), replacement) +} + +/** + * Replace part of string before the last occurrence of given delimiter with the [replacement] string. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.replaceBeforeLast(delimiter: Char, replacement: String, missingDelimiterValue: String = this): String { + val index = lastIndexOf(delimiter) + return if (index == -1) missingDelimiterValue else replaceRange(0, index, replacement) +} + +/** + * Replace part of string before the last occurrence of given delimiter with the [replacement] string. + * If the string does not contain the delimiter, returns [missingDelimiterValue] which defaults to the original string. + */ +public fun String.replaceBeforeLast(delimiter: String, replacement: String, missingDelimiterValue: String = this): String { + val index = lastIndexOf(delimiter) + return if (index == -1) missingDelimiterValue else replaceRange(0, index, replacement) +} +*/ + +/** + * Returns a new string obtained by replacing each substring of this string that matches the given regular expression + * with the given [replacement]. + * + * The [replacement] can consist of any combination of literal text and $-substitutions. To treat the replacement string + * literally escape it with the [kotlin.text.Regex.Companion.escapeReplacement] method. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.replace(regex: Regex, replacement: String): String = regex.replace(this, replacement) + +/** + * Returns a new string obtained by replacing each substring of this string that matches the given regular expression + * with the result of the given function [transform] that takes [MatchResult] and returns a string to be used as a + * replacement for that match. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.replace(regex: Regex, transform: (MatchResult) -> String): String = regex.replace(this, transform) + +/** + * Replaces the first occurrence of the given regular expression [regex] in this string with specified [replacement] expression. + * + * @param replacement A replacement expression that can include substitutions. See [Regex.replaceFirst] for details. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.replaceFirst(regex: Regex, replacement: String): String = regex.replaceFirst(this, replacement) + + +/** + * Returns `true` if this string matches the given regular expression. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.matches(regex: Regex): Boolean = regex.matches(this) + + +/** + * Returns `true` if this string starts with the specified character. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.startsWith(char: Char, ignoreCase: Boolean = false): Boolean = + this.length() > 0 && this[0].equals(char, ignoreCase) + +/** + * Returns `true` if this string ends with the specified character. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.endsWith(char: Char, ignoreCase: Boolean = false): Boolean = + this.length() > 0 && this[lastIndex].equals(char, ignoreCase) + + + + + +// indexOfAny() + +private fun String.findAnyOf(chars: CharArray, startIndex: Int, ignoreCase: Boolean, last: Boolean): Pair? { + if (!ignoreCase && chars.size() == 1) { + val char = chars.single() + val index = if (!last) nativeIndexOf(char, startIndex) else nativeLastIndexOf(char, startIndex) + return if (index < 0) null else index to char + } + + val indices = if (!last) Math.max(startIndex, 0)..lastIndex else Math.min(startIndex, lastIndex) downTo 0 + for (index in indices) { + val charAtIndex = get(index) + val matchingCharIndex = chars.indexOfFirst { it.equals(charAtIndex, ignoreCase) } + if (matchingCharIndex >= 0) + return index to chars[matchingCharIndex] + } + + return null +} + +/** + * Finds the index of the first occurrence of any of the specified [chars] in this string, starting from the specified [startIndex] and + * optionally ignoring the case. + * + * @param ignoreCase `true` to ignore character case when matching a character. By default `false`. + * @returns An index of the first occurrence of matched character from [chars] or -1 if none of [chars] are found. + * + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.indexOfAny(chars: CharArray, startIndex: Int = 0, ignoreCase: Boolean = false): Int = + findAnyOf(chars, startIndex, ignoreCase, last = false)?.first ?: -1 + +/** + * Finds the index of the last occurrence of any of the specified [chars] in this string, starting from the specified [startIndex] and + * optionally ignoring the case. + * + * @param startIndex The index of character to start searching at. The search proceeds backward toward the beginning of the string. + * @param ignoreCase `true` to ignore character case when matching a character. By default `false`. + * @returns An index of the last occurrence of matched character from [chars] or -1 if none of [chars] are found. + * + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.lastIndexOfAny(chars: CharArray, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int = + findAnyOf(chars, startIndex, ignoreCase, last = true)?.first ?: -1 + + +/* +private fun String.findAnyOf(strings: Collection, startIndex: Int, ignoreCase: Boolean, last: Boolean): Pair? { + if (!ignoreCase && strings.size() == 1) { + val string = strings.single() + val index = if (!last) nativeIndexOf(string, startIndex) else nativeLastIndexOf(string, startIndex) + return if (index < 0) null else index to string + } + + val indices = if (!last) Math.max(startIndex, 0)..length() else Math.min(startIndex, lastIndex) downTo 0 + for (index in indices) { + val matchingString = strings.firstOrNull { it.regionMatches(0, this, index, it.length(), ignoreCase) } + if (matchingString != null) + return index to matchingString + } + + return null +} + +/** + * Finds the first occurrence of any of the specified [strings] in this string, starting from the specified [startIndex] and + * optionally ignoring the case. + * + * @param ignoreCase `true` to ignore character case when matching a string. By default `false`. + * @returns A pair of an index of the first occurrence of matched string from [strings] and the string matched or `null` if none of [strings] are found. + * + * To avoid ambiguous results when strings in [strings] have characters in common, this method proceeds from + * the beginning to the end of this string, and finds at each position the first element in [strings] + * that matches this string at that position. + */ +public fun String.findAnyOf(strings: Collection, startIndex: Int = 0, ignoreCase: Boolean = false): Pair? = + findAnyOf(strings, startIndex, ignoreCase, last = false) + +/** + * Finds the last occurrence of any of the specified [strings] in this string, starting from the specified [startIndex] and + * optionally ignoring the case. + * + * @param startIndex The index of character to start searching at. The search proceeds backward toward the beginning of the string. + * @param ignoreCase `true` to ignore character case when matching a string. By default `false`. + * @returns A pair of an index of the last occurrence of matched string from [strings] and the string matched or `null` if none of [strings] are found. + * + * To avoid ambiguous results when strings in [strings] have characters in common, this method proceeds from + * the end toward the beginning of this string, and finds at each position the first element in [strings] + * that matches this string at that position. + */ +public fun String.findLastAnyOf(strings: Collection, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Pair? = + findAnyOf(strings, startIndex, ignoreCase, last = true) + +/** + * Finds the index of the first occurrence of any of the specified [strings] in this string, starting from the specified [startIndex] and + * optionally ignoring the case. + * + * @param ignoreCase `true` to ignore character case when matching a string. By default `false`. + * @returns An index of the first occurrence of matched string from [strings] or -1 if none of [strings] are found. + * + * To avoid ambiguous results when strings in [strings] have characters in common, this method proceeds from + * the beginning to the end of this string, and finds at each position the first element in [strings] + * that matches this string at that position. + */ +public fun String.indexOfAny(strings: Collection, startIndex: Int = 0, ignoreCase: Boolean = false): Int = + findAnyOf(strings, startIndex, ignoreCase, last = false)?.first ?: -1 + +/** + * Finds the index of the last occurrence of any of the specified [strings] in this string, starting from the specified [startIndex] and + * optionally ignoring the case. + * + * @param startIndex The index of character to start searching at. The search proceeds backward toward the beginning of the string. + * @param ignoreCase `true` to ignore character case when matching a string. By default `false`. + * @returns An index of the last occurrence of matched string from [strings] or -1 if none of [strings] are found. + * + * To avoid ambiguous results when strings in [strings] have characters in common, this method proceeds from + * the end toward the beginning of this string, and finds at each position the first element in [strings] + * that matches this string at that position. + */ +public fun String.lastIndexOfAny(strings: Collection, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int = + findAnyOf(strings, startIndex, ignoreCase, last = true)?.first ?: -1 +*/ + +// indexOf + +/** + * Returns the index within this string of the first occurrence of the specified character, starting from the specified [startIndex]. + * + * @param ignoreCase `true` to ignore character case when matching a character. By default `false`. + * @returns An index of the first occurrence of [char] or -1 if none is found. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.indexOf(char: Char, startIndex: Int = 0, ignoreCase: Boolean = false): Int { + return if (ignoreCase) + indexOfAny(charArrayOf(char), startIndex, ignoreCase) + else + nativeIndexOf(char, startIndex) +} + +/* +/** + * Returns the index within this string of the first occurrence of the specified [string], starting from the specified [startIndex]. + * + * @param ignoreCase `true` to ignore character case when matching a string. By default `false`. + * @returns An index of the first occurrence of [string] or -1 if none is found. + */ +@kotlin.jvm.JvmOverloads +public fun String.indexOf(string: String, startIndex: Int = 0, ignoreCase: Boolean = false): Int { + return if (ignoreCase) + indexOfAny(listOf(string), startIndex, ignoreCase) + else + nativeIndexOf(string, startIndex) +} +*/ +/** + * Returns the index within this string of the last occurrence of the specified character, starting from the specified [startIndex]. + * + * @param startIndex The index of character to start searching at. The search proceeds backward toward the beginning of the string. + * @param ignoreCase `true` to ignore character case when matching a character. By default `false`. + * @returns An index of the first occurrence of [char] or -1 if none is found. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public fun String.lastIndexOf(char: Char, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int { + return if (ignoreCase) + lastIndexOfAny(charArrayOf(char), startIndex, ignoreCase) + else + nativeLastIndexOf(char, startIndex) +} + +/* +/** + * Returns the index within this string of the last occurrence of the specified [string], starting from the specified [startIndex]. + * + * @param startIndex The index of character to start searching at. The search proceeds backward toward the beginning of the string. + * @param ignoreCase `true` to ignore character case when matching a string. By default `false`. + * @returns An index of the first occurrence of [string] or -1 if none is found. + */ +public fun String.lastIndexOf(string: String, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int { + return if (ignoreCase) + lastIndexOfAny(listOf(string), startIndex, ignoreCase) + else + nativeLastIndexOf(string, startIndex) +} + +/** + * Returns `true` if this string contains the specified sequence of characters as a substring. + * + * @param ignoreCase `true` to ignore character case when comparing strings. By default `false`. + */ +public operator fun String.contains(seq: CharSequence, ignoreCase: Boolean = false): Boolean = + indexOf(seq.toString(), ignoreCase = ignoreCase) >= 0 + + +/** + * Returns `true` if this string contains the specified character. + * + * @param ignoreCase `true` to ignore character case when comparing characters. By default `false`. + */ +public operator fun String.contains(char: Char, ignoreCase: Boolean = false): Boolean = + indexOf(char, ignoreCase = ignoreCase) >= 0 +*/ + +// rangesDelimitedBy + +/* +private class DelimitedRangesSequence(private val string: String, private val startIndex: Int, private val limit: Int, private val getNextMatch: String.(Int) -> Pair?): Sequence { + + override fun iterator(): Iterator = object : Iterator { + var nextState: Int = -1 // -1 for unknown, 0 for done, 1 for continue + var currentStartIndex: Int = Math.min(Math.max(startIndex, 0), string.length()) + var nextSearchIndex: Int = currentStartIndex + var nextItem: IntRange? = null + var counter: Int = 0 + + private fun calcNext() { + if (nextSearchIndex < 0) { + nextState = 0 + nextItem = null + } + else { + if (limit > 0 && ++counter >= limit || nextSearchIndex > string.length()) { + nextItem = currentStartIndex..string.lastIndex + nextSearchIndex = -1 + } + else { + val match = string.getNextMatch(nextSearchIndex) + if (match == null) { + nextItem = currentStartIndex..string.lastIndex + nextSearchIndex = -1 + } + else { + val (index,length) = match + nextItem = currentStartIndex..index-1 + currentStartIndex = index + length + nextSearchIndex = currentStartIndex + if (length == 0) 1 else 0 + } + } + nextState = 1 + } + } + + override fun next(): IntRange { + if (nextState == -1) + calcNext() + if (nextState == 0) + throw NoSuchElementException() + val result = nextItem as IntRange + // Clean next to avoid keeping reference on yielded instance + nextItem = null + nextState = -1 + return result + } + + override fun hasNext(): Boolean { + if (nextState == -1) + calcNext() + return nextState == 1 + } + } +} + + +/** + * Returns a sequence of index ranges of substrings in this string around occurrences of the specified [delimiters]. + * + * @param delimiters One or more characters to be used as delimiters. + * @param startIndex The index to start searching delimiters from. + * No range having its start value less than [startIndex] is returned. + * [startIndex] is coerced to be non-negative and not greater than length of this string. + * @param ignoreCase `true` to ignore character case when matching a delimiter. By default `false`. + * @param limit The maximum number of substrings to return. Zero by default means no limit is set. + */ +private fun String.rangesDelimitedBy(vararg delimiters: Char, startIndex: Int = 0, ignoreCase: Boolean = false, limit: Int = 0): Sequence { + require(limit >= 0, { "Limit must be non-negative, but was $limit" }) + + return DelimitedRangesSequence(this, startIndex, limit, { startIndex -> findAnyOf(delimiters, startIndex, ignoreCase = ignoreCase, last = false)?.let { it.first to 1 } }) +} + + +/** + * Returns a sequence of index ranges of substrings in this string around occurrences of the specified [delimiters]. + * + * @param delimiters One or more strings to be used as delimiters. + * @param startIndex The index to start searching delimiters from. + * No range having its start value less than [startIndex] is returned. + * [startIndex] is coerced to be non-negative and not greater than length of this string. + * @param ignoreCase `true` to ignore character case when matching a delimiter. By default `false`. + * @param limit The maximum number of substrings to return. Zero by default means no limit is set. + * + * To avoid ambiguous results when strings in [delimiters] have characters in common, this method proceeds from + * the beginning to the end of this string, and finds at each position the first element in [delimiters] + * that matches this string at that position. + */ +private fun String.rangesDelimitedBy(vararg delimiters: String, startIndex: Int = 0, ignoreCase: Boolean = false, limit: Int = 0): Sequence { + require(limit >= 0, { "Limit must be non-negative, but was $limit" } ) + val delimitersList = delimiters.asList() + + return DelimitedRangesSequence(this, startIndex, limit, { startIndex -> findAnyOf(delimitersList, startIndex, ignoreCase = ignoreCase, last = false)?.let { it.first to it.second.length ()} }) + +} + + +// split + +/** + * Splits this string to a sequence of strings around occurrences of the specified [delimiters]. + * + * @param delimiters One or more strings to be used as delimiters. + * @param ignoreCase `true` to ignore character case when matching a delimiter. By default `false`. + * @param limit The maximum number of substrings to return. Zero by default means no limit is set. + * + * To avoid ambiguous results when strings in [delimiters] have characters in common, this method proceeds from + * the beginning to the end of this string, and finds at each position the first element in [delimiters] + * that matches this string at that position. + */ +public fun String.splitToSequence(vararg delimiters: String, ignoreCase: Boolean = false, limit: Int = 0): Sequence = + rangesDelimitedBy(*delimiters, ignoreCase = ignoreCase, limit = limit) map { substring(it) } + +/** + * Splits this string to a list of strings around occurrences of the specified [delimiters]. + * + * @param delimiters One or more strings to be used as delimiters. + * @param ignoreCase `true` to ignore character case when matching a delimiter. By default `false`. + * @param limit The maximum number of substrings to return. Zero by default means no limit is set. + * + * To avoid ambiguous results when strings in [delimiters] have characters in common, this method proceeds from + * the beginning to the end of this string, and matches at each position the first element in [delimiters] + * that is equal to a delimiter in this instance at that position. + */ +public fun String.split(vararg delimiters: String, ignoreCase: Boolean = false, limit: Int = 0): List = + splitToSequence(*delimiters, ignoreCase = ignoreCase, limit = limit).toList() + +/** + * Splits this string to a sequence of strings around occurrences of the specified [delimiters]. + * + * @param delimiters One or more characters to be used as delimiters. + * @param ignoreCase `true` to ignore character case when matching a delimiter. By default `false`. + * @param limit The maximum number of substrings to return. + */ +public fun String.splitToSequence(vararg delimiters: Char, ignoreCase: Boolean = false, limit: Int = 0): Sequence = + rangesDelimitedBy(*delimiters, ignoreCase = ignoreCase, limit = limit) map { substring(it) } + +/** + * Splits this string to a list of strings around occurrences of the specified [delimiters]. + * + * @param delimiters One or more characters to be used as delimiters. + * @param ignoreCase `true` to ignore character case when matching a delimiter. By default `false`. + * @param limit The maximum number of substrings to return. + */ +public fun String.split(vararg delimiters: Char, ignoreCase: Boolean = false, limit: Int = 0): List = + splitToSequence(*delimiters, ignoreCase = ignoreCase, limit = limit).toList() + +/** + * Splits this string around matches of the given regular expression. + * + * @param limit Non-negative value specifying the maximum number of substrings to return. + * Zero by default means no limit is set. + */ +public fun String.split(pattern: Regex, limit: Int = 0): List = pattern.split(this, limit) + +/** + * Splits this string to a sequence of lines delimited by any of the following character sequences: CRLF, LF or CR. + */ +public fun String.lineSequence(): Sequence = splitToSequence("\r\n", "\n", "\r") + +/** + * * Splits this string to a list of lines delimited by any of the following character sequences: CRLF, LF or CR. + */ +public fun String.lines(): List = lineSequence().toList() + +*/ diff --git a/libraries/stdlib/src/kotlin/text/StringsDeprecatedJVM.kt b/libraries/stdlib/src/kotlin/text/StringsDeprecatedJVM.kt new file mode 100644 index 00000000000..371f3e55408 --- /dev/null +++ b/libraries/stdlib/src/kotlin/text/StringsDeprecatedJVM.kt @@ -0,0 +1,446 @@ +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("StringsKt") + +package kotlin + +import java.io.StringReader +import java.util.regex.Pattern +import java.nio.charset.Charset +import java.util.* + +/* +/** + * Returns `true` if this string is equal to [anotherString], optionally ignoring character case. + * + * @param ignoreCase `true` to ignore character case when comparing strings. By default `false`. + */ +public fun String.equals(anotherString: String, ignoreCase: Boolean = false): Boolean { + return if (!ignoreCase) + (this as java.lang.String).equals(anotherString) + else + (this as java.lang.String).equalsIgnoreCase(anotherString) +} + +/** + * Returns a new string with all occurrences of [oldChar] replaced with [newChar]. + */ +public fun String.replace(oldChar: Char, newChar: Char, ignoreCase: Boolean = false): String { + if (!ignoreCase) + return (this as java.lang.String).replace(oldChar, newChar) + else + return splitToSequence(oldChar, ignoreCase = ignoreCase).joinToString(separator = newChar.toString()) +} + +/** + * Returns a new string obtained by replacing all occurrences of the [oldValue] substring in this string + * with the specified [newValue] string. + */ +public fun String.replace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String = + splitToSequence(oldValue, ignoreCase = ignoreCase).joinToString(separator = newValue) + + +/** + * Returns a new string with the first occurrence of [oldChar] replaced with [newChar]. + */ +public fun String.replaceFirst(oldChar: Char, newChar: Char, ignoreCase: Boolean = false): String { + val index = indexOf(oldChar, ignoreCase = ignoreCase) + return if (index < 0) this else this.replaceRange(index, index + 1, newChar.toString()) +} + +/** + * Returns a new string obtained by replacing the first occurrence of the [oldValue] substring in this string + * with the specified [newValue] string. + */ +public fun String.replaceFirst(oldValue: String, newValue: String, ignoreCase: Boolean = false): String { + val index = indexOf(oldValue, ignoreCase = ignoreCase) + return if (index < 0) this else this.replaceRange(index, index + oldValue.length(), newValue) +} + +/** + * Returns a copy of this string converted to upper case using the rules of the default locale. + */ +public fun String.toUpperCase(): String = (this as java.lang.String).toUpperCase() + +/** + * Returns a copy of this string converted to lower case using the rules of the default locale. + */ +public fun String.toLowerCase(): String = (this as java.lang.String).toLowerCase() + +/** + * Returns a new character array containing the characters from this string. + */ +public fun String.toCharArray(): CharArray = (this as java.lang.String).toCharArray() + +/** + * Uses this string as a format string and returns a string obtained by substituting the specified arguments, + * using the default locale. + */ +public fun String.format(vararg args: Any?): String = java.lang.String.format(this, *args) + +/** + * Uses this string as a format string and returns a string obtained by substituting the specified arguments, using + * the specified locale. + */ +public fun String.format(locale: Locale, vararg args : Any?) : String = java.lang.String.format(locale, this, *args) + +/** + * Splits this string around matches of the given regular expression. + + * @param limit Non-negative value specifying the maximum number of substrings to return. + * Zero by default means no limit is set. + */ +public fun String.split(regex: Pattern, limit: Int = 0): List +{ + require(limit >= 0, { "Limit must be non-negative, but was $limit" } ) + return regex.split(this, if (limit == 0) -1 else limit).asList() +} + +/** + * Returns a substring of this string starting with the specified index. + */ +public fun String.substring(beginIndex: Int): String = (this as java.lang.String).substring(beginIndex) + +/** + * Returns the substring of this string starting and ending at the specified indices. + */ +public fun String.substring(beginIndex: Int, endIndex: Int): String = (this as java.lang.String).substring(beginIndex, endIndex) + +/** + * Returns `true` if this string starts with the specified prefix. + */ +public fun String.startsWith(prefix: String, ignoreCase: Boolean = false): Boolean { + if (!ignoreCase) + return (this as java.lang.String).startsWith(prefix) + else + return regionMatches(0, prefix, 0, prefix.length(), ignoreCase) +} + +/** + * Returns `true` if a substring of this string starting at the specified offset [thisOffset] starts with the specified prefix. + */ +public fun String.startsWith(prefix: String, thisOffset: Int, ignoreCase: Boolean = false): Boolean { + if (!ignoreCase) + return (this as java.lang.String).startsWith(prefix, thisOffset) + else + return regionMatches(thisOffset, prefix, 0, prefix.length(), ignoreCase) +} + +/** + * Returns `true` if this string ends with the specified suffix. + */ +public fun String.endsWith(suffix: String, ignoreCase: Boolean = false): Boolean { + if (!ignoreCase) + return (this as java.lang.String).endsWith(suffix) + else + return regionMatches(length() - suffix.length(), suffix, 0, suffix.length(), ignoreCase = true) +} + +// "constructors" for String + +/** + * Converts the data from a portion of the specified array of bytes to characters using the specified character set + * and returns the conversion result as a string. + * + * @param bytes the source array for the conversion. + * @param offset the offset in the array of the data to be converted. + * @param length the number of bytes to be converted. + * @param charsetName the name of the character set to use. + */ +public fun String(bytes: ByteArray, offset: Int, length: Int, charsetName: String): String = java.lang.String(bytes, offset, length, charsetName) as String + +/** + * Converts the data from a portion of the specified array of bytes to characters using the specified character set + * and returns the conversion result as a string. + * + * @param bytes the source array for the conversion. + * @param offset the offset in the array of the data to be converted. + * @param length the number of bytes to be converted. + * @param charset the character set to use. + */ +public fun String(bytes: ByteArray, offset: Int, length: Int, charset: Charset): String = java.lang.String(bytes, offset, length, charset) as String + +/** + * Converts the data from the specified array of bytes to characters using the specified character set + * and returns the conversion result as a string. + */ +public fun String(bytes: ByteArray, charsetName: String): String = java.lang.String(bytes, charsetName) as String + +/** + * Converts the data from the specified array of bytes to characters using the specified character set + * and returns the conversion result as a string. + */ +public fun String(bytes: ByteArray, charset: Charset): String = java.lang.String(bytes, charset) as String + +/** + * Converts the data from a portion of the specified array of bytes to characters using the UTF-8 character set + * and returns the conversion result as a string. + * + * @param bytes the source array for the conversion. + * @param offset the offset in the array of the data to be converted. + * @param length the number of bytes to be converted. + */ +public fun String(bytes: ByteArray, offset: Int, length: Int): String = java.lang.String(bytes, offset, length, Charsets.UTF_8) as String + +/** + * Converts the data from the specified array of bytes to characters using the UTF-8 character set + * and returns the conversion result as a string. + */ +public fun String(bytes: ByteArray): String = java.lang.String(bytes, Charsets.UTF_8) as String + +/** + * Converts the characters in the specified array to a string. + */ +public fun String(chars: CharArray): String = java.lang.String(chars) as String + +/** + * Converts the characters from a portion of the specified array to a string. + */ +public fun String(chars: CharArray, offset: Int, length: Int): String = java.lang.String(chars, offset, length) as String + +/** + * Converts the code points from a portion of the specified Unicode code point array to a string. + */ +public fun String(codePoints: IntArray, offset: Int, length: Int): String = java.lang.String(codePoints, offset, length) as String + +/** + * Converts the contents of the specified StringBuffer to a string. + */ +public fun String(stringBuffer: java.lang.StringBuffer): String = java.lang.String(stringBuffer) as String + +/** + * Converts the contents of the specified StringBuilder to a string. + */ +public fun String(stringBuilder: java.lang.StringBuilder): String = java.lang.String(stringBuilder) as String + +///** +// * Replaces the first substring of this string that matches the given regular expression with the given replacement. +// */ +//deprecated("Use replaceFirst(Regex, String) or replaceFirstLiteral(String, String) instead.", ReplaceWith("replaceFirst(regex.toRegex(), replacement)")) +//public fun String.replaceFirst(regex: String, replacement: String): String = (this as java.lang.String).replaceFirst(regex, replacement) + +/** + * Returns the character (Unicode code point) at the specified index. + */ +public fun String.codePointAt(index: Int): Int = (this as java.lang.String).codePointAt(index) + +/** + * Returns the character (Unicode code point) before the specified index. + */ +public fun String.codePointBefore(index: Int): Int = (this as java.lang.String).codePointBefore(index) + +/** + * Returns the number of Unicode code points in the specified text range of this String. + */ +public fun String.codePointCount(beginIndex: Int, endIndex: Int): Int = (this as java.lang.String).codePointCount(beginIndex, endIndex) + +/** + * Compares two strings lexicographically, optionally ignoring case differences. + */ +public fun String.compareTo(other: String, ignoreCase: Boolean = false): Int { + if (ignoreCase) + return (this as java.lang.String).compareToIgnoreCase(other) + else + return (this as java.lang.String).compareTo(other) +} + +/** + * Returns a new string obtained by concatenating this string and the specified string. + */ +public fun String.concat(str: String): String = (this as java.lang.String).concat(str) + +/** + * Returns `true` if this string is equal to the contents of the specified CharSequence. + */ +public fun String.contentEquals(cs: CharSequence): Boolean = (this as java.lang.String).contentEquals(cs) + +/** + * Returns `true` if this string is equal to the contents of the specified StringBuffer. + */ +public fun String.contentEquals(sb: StringBuffer): Boolean = (this as java.lang.String).contentEquals(sb) + +/** + * Copies the characters from a substring of this string into the specified character array. + * @param srcBegin the start offset (inclusive) of the substring to copy. + * @param srcEnd the end offset (exclusive) of the substring to copy. + * @param dst the array to copy to. + * @param dstBegin the position in the array to copy to. + */ +public fun String.getChars(srcBegin: Int, srcEnd: Int, dst: CharArray, dstBegin: Int): Unit = (this as java.lang.String).getChars(srcBegin, srcEnd, dst, dstBegin) + + +/** + * Returns a canonical representation for this string object. + */ +public fun String.intern(): String = (this as java.lang.String).intern() + +/** + * Returns `true` if this string is empty or consists solely of whitespace characters. + */ +public fun String.isBlank(): Boolean = length() == 0 || all { it.isWhitespace() } + +/** + * Returns the index within this string that is offset from the given [index] by [codePointOffset] code points. + */ +public fun String.offsetByCodePoints(index: Int, codePointOffset: Int): Int = (this as java.lang.String).offsetByCodePoints(index, codePointOffset) + +/** + * Returns `true` if the specified range in this string is equal to the specified range in another string. + * @param thisOffset the start offset in this string of the substring to compare. + * @param other the string against a substring of which the comparison is performed. + * @param otherOffset the start offset in the other string of the substring to compare. + * @param length the length of the substring to compare. + */ +public fun String.regionMatches(thisOffset: Int, other: String, otherOffset: Int, length: Int, ignoreCase: Boolean = false): Boolean = + if (!ignoreCase) + (this as java.lang.String).regionMatches(thisOffset, other, otherOffset, length) + else + (this as java.lang.String).regionMatches(ignoreCase, thisOffset, other, otherOffset, length) + +/** + * Returns a copy of this string converted to lower case using the rules of the specified locale. + */ +public fun String.toLowerCase(locale: java.util.Locale): String = (this as java.lang.String).toLowerCase(locale) + +/** + * Returns a copy of this string converted to upper case using the rules of the specified locale. + */ +public fun String.toUpperCase(locale: java.util.Locale): String = (this as java.lang.String).toUpperCase(locale) + +/** + * Returns `true` if the contents of this string is equal to the word "true", ignoring case, and `false` otherwise. + */ +public fun String.toBoolean(): Boolean = java.lang.Boolean.parseBoolean(this) + +/** + * Parses the string as a [Short] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +public fun String.toShort(): Short = java.lang.Short.parseShort(this) + +/** + * Parses the string as an [Int] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +public fun String.toInt(): Int = java.lang.Integer.parseInt(this) + +/** + * Parses the string as a [Long] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +public fun String.toLong(): Long = java.lang.Long.parseLong(this) + +/** + * Parses the string as a [Float] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +public fun String.toFloat(): Float = java.lang.Float.parseFloat(this) + +/** + * Parses the string as a [Double] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +public fun String.toDouble(): Double = java.lang.Double.parseDouble(this) + +/** + * Returns the list of all characters in this string. + */ +public fun String.toCharList(): List = toCharArray().toList() + +/** + * Returns a subsequence of this sequence. + * + * @param start the start index (inclusive). + * @param end the end index (exclusive). + */ +public operator fun CharSequence.get(start: Int, end: Int): CharSequence = subSequence(start, end) + +/** + * Encodes the contents of this string using the specified character set and returns the resulting byte array. + */ +public fun String.toByteArray(charset: String): ByteArray = (this as java.lang.String).getBytes(charset) + +/** + * Encodes the contents of this string using the specified character set and returns the resulting byte array. + */ +public fun String.toByteArray(charset: Charset = Charsets.UTF_8): ByteArray = (this as java.lang.String).getBytes(charset) + +/** + * Returns a subsequence of this sequence specified by given [range]. + */ +public fun CharSequence.slice(range: IntRange): CharSequence { + return subSequence(range.start, range.end + 1) // inclusive +} + +/** + * Converts the string into a regular expression [Pattern] optionally + * with the specified [flags] from [Pattern] or'd together + * so that strings can be split or matched on. + */ +public fun String.toPattern(flags: Int = 0): java.util.regex.Pattern { + return java.util.regex.Pattern.compile(this, flags) +} + +/** + * 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. + * + * @sample test.text.StringTest.capitalize + */ +public fun String.capitalize(): String { + return if (isNotEmpty() && charAt(0).isLowerCase()) substring(0, 1).toUpperCase() + substring(1) else this +} + +/** + * 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. + * + * @sample test.text.StringTest.decapitalize + */ +public fun String.decapitalize(): String { + return if (isNotEmpty() && charAt(0).isUpperCase()) substring(0, 1).toLowerCase() + substring(1) else this +} + +/** + * Repeats a given string [n] times. + * @throws [IllegalArgumentException] when n < 0. + * @sample test.text.StringJVMTest.repeat + */ +public fun String.repeat(n: Int): String { + if (n < 0) + throw IllegalArgumentException("Value should be non-negative, but was $n") + + val sb = StringBuilder() + for (i in 1..n) { + sb.append(this) + } + return sb.toString() +} +*/ + +/** + * Appends the contents of this string, excluding the first characters that satisfy the given [predicate], + * to the given Appendable. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public inline fun String.dropWhileTo(result: T, predicate: (Char) -> Boolean): T { + var start = true + for (element in this) { + if (start && predicate(element)) { + // ignore + } else { + start = false + result.append(element) + } + } + return result +} + +/** + * Appends the first characters from this string that satisfy the given [predicate] to the given Appendable. + */ +@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) +public inline fun String.takeWhileTo(result: T, predicate: (Char) -> Boolean): T { + for (c in this) if (predicate(c)) result.append(c) else break + return result +} +