Generalize String extensions to take CharSequence as receiver and parameters where applicable.
This commit is contained in:
@@ -11,7 +11,7 @@ import kotlin.text.Regex
|
||||
/**
|
||||
* Returns the string with leading and trailing characters matching the [predicate] trimmed.
|
||||
*/
|
||||
inline public fun String.trim(predicate: (Char) -> Boolean): String {
|
||||
inline public fun CharSequence.trim(predicate: (Char) -> Boolean): String {
|
||||
var startIndex = 0
|
||||
var endIndex = length() - 1
|
||||
var startFound = false
|
||||
@@ -40,7 +40,7 @@ inline public fun String.trim(predicate: (Char) -> Boolean): String {
|
||||
/**
|
||||
* Returns the string with leading characters matching the [predicate] trimmed.
|
||||
*/
|
||||
inline public fun String.trimStart(predicate: (Char) -> Boolean): String {
|
||||
inline public fun CharSequence.trimStart(predicate: (Char) -> Boolean): String {
|
||||
for (index in this.indices)
|
||||
if (!predicate(this[index]))
|
||||
return substring(index)
|
||||
@@ -51,7 +51,7 @@ inline public fun String.trimStart(predicate: (Char) -> Boolean): String {
|
||||
/**
|
||||
* Returns the string with trailing characters matching the [predicate] trimmed.
|
||||
*/
|
||||
inline public fun String.trimEnd(predicate: (Char) -> Boolean): String {
|
||||
inline public fun CharSequence.trimEnd(predicate: (Char) -> Boolean): String {
|
||||
for (index in this.indices.reversed())
|
||||
if (!predicate(this[index]))
|
||||
return substring(0, index + 1)
|
||||
@@ -62,32 +62,32 @@ inline public fun String.trimEnd(predicate: (Char) -> Boolean): String {
|
||||
/**
|
||||
* Returns the string with leading and trailing characters in the [chars] array trimmed.
|
||||
*/
|
||||
public fun String.trim(vararg chars: Char): String = trim { it in chars }
|
||||
public fun CharSequence.trim(vararg chars: Char): String = trim { it in chars }
|
||||
|
||||
/**
|
||||
* Returns the string with leading and trailing characters in the [chars] array trimmed.
|
||||
*/
|
||||
public fun String.trimStart(vararg chars: Char): String = trimStart { it in chars }
|
||||
public fun CharSequence.trimStart(vararg chars: Char): String = trimStart { it in chars }
|
||||
|
||||
/**
|
||||
* Returns the string with trailing characters in the [chars] array trimmed.
|
||||
*/
|
||||
public fun String.trimEnd(vararg chars: Char): String = trimEnd { it in chars }
|
||||
public fun CharSequence.trimEnd(vararg chars: Char): String = trimEnd { it in chars }
|
||||
|
||||
/**
|
||||
* Returns a string with leading and trailing whitespace trimmed.
|
||||
*/
|
||||
public fun String.trim(): String = trim { it.isWhitespace() }
|
||||
public fun CharSequence.trim(): String = trim { it.isWhitespace() }
|
||||
|
||||
/**
|
||||
* Returns a string with leading whitespace removed.
|
||||
*/
|
||||
public fun String.trimStart(): String = trimStart { it.isWhitespace() }
|
||||
public fun CharSequence.trimStart(): String = trimStart { it.isWhitespace() }
|
||||
|
||||
/**
|
||||
* Returns a string with trailing whitespace removed.
|
||||
*/
|
||||
public fun String.trimEnd(): String = trimEnd { it.isWhitespace() }
|
||||
public fun CharSequence.trimEnd(): String = trimEnd { it.isWhitespace() }
|
||||
|
||||
/**
|
||||
* Left pad a String with a specified character or space.
|
||||
@@ -97,11 +97,11 @@ public fun String.trimEnd(): String = trimEnd { it.isWhitespace() }
|
||||
* @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.
|
||||
*/
|
||||
public fun String.padStart(length: Int, padChar: Char = ' '): String {
|
||||
public fun CharSequence.padStart(length: Int, padChar: Char = ' '): String {
|
||||
if (length < 0)
|
||||
throw IllegalArgumentException("String length $length is less than zero.")
|
||||
if (length <= this.length())
|
||||
return this
|
||||
return this.toString()
|
||||
|
||||
val sb = StringBuilder(length)
|
||||
for (i in 1..(length - this.length()))
|
||||
@@ -118,11 +118,11 @@ public fun String.padStart(length: Int, padChar: Char = ' '): String {
|
||||
* @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.
|
||||
*/
|
||||
public fun String.padEnd(length: Int, padChar: Char = ' '): String {
|
||||
public fun CharSequence.padEnd(length: Int, padChar: Char = ' '): String {
|
||||
if (length < 0)
|
||||
throw IllegalArgumentException("String length $length is less than zero.")
|
||||
if (length <= this.length())
|
||||
return this
|
||||
return this.toString()
|
||||
|
||||
val sb = StringBuilder(length)
|
||||
sb.append(this)
|
||||
@@ -134,22 +134,22 @@ public fun String.padEnd(length: Int, padChar: Char = ' '): String {
|
||||
/** 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 String?.isNotEmpty(): Boolean = this != null && this.length() > 0
|
||||
public fun CharSequence?.isNotEmpty(): Boolean = this != null && this.length() > 0
|
||||
|
||||
/**
|
||||
* Returns `true` if this nullable string is either `null` or empty.
|
||||
*/
|
||||
public fun String?.isNullOrEmpty(): Boolean = this == null || this.length() == 0
|
||||
public fun CharSequence?.isNullOrEmpty(): Boolean = this == null || this.length() == 0
|
||||
|
||||
/**
|
||||
* Returns `true` if this string is empty (contains no characters).
|
||||
*/
|
||||
public fun String.isEmpty(): Boolean = length() == 0
|
||||
public fun CharSequence.isEmpty(): Boolean = length() == 0
|
||||
|
||||
/**
|
||||
* Returns `true` if this string is not empty.
|
||||
*/
|
||||
public fun String.isNotEmpty(): Boolean = length() > 0
|
||||
public fun CharSequence.isNotEmpty(): Boolean = length() > 0
|
||||
|
||||
// implemented differently in JVM and JS
|
||||
//public fun String.isBlank(): Boolean = length() == 0 || all { it.isWhitespace() }
|
||||
@@ -158,12 +158,12 @@ public fun String.isNotEmpty(): Boolean = length() > 0
|
||||
/**
|
||||
* Returns `true` if this string is not empty and contains some characters except of whitespace characters.
|
||||
*/
|
||||
public fun String.isNotBlank(): Boolean = !isBlank()
|
||||
public fun CharSequence.isNotBlank(): Boolean = !isBlank()
|
||||
|
||||
/**
|
||||
* Returns `true` if this nullable string is either `null` or empty or consists solely of whitespace characters.
|
||||
*/
|
||||
public fun String?.isNullOrBlank(): Boolean = this == null || this.isBlank()
|
||||
public fun CharSequence?.isNullOrBlank(): Boolean = this == null || this.isBlank()
|
||||
|
||||
/**
|
||||
* Iterator for characters of given CharSequence.
|
||||
@@ -182,13 +182,13 @@ public fun String?.orEmpty(): String = this ?: ""
|
||||
/**
|
||||
* Returns the range of valid character indices for this string.
|
||||
*/
|
||||
public val String.indices: IntRange
|
||||
public val CharSequence.indices: IntRange
|
||||
get() = 0..length() - 1
|
||||
|
||||
/**
|
||||
* Returns the index of the last character in the String or -1 if the String is empty.
|
||||
*/
|
||||
public val String.lastIndex: Int
|
||||
public val CharSequence.lastIndex: Int
|
||||
get() = this.length() - 1
|
||||
|
||||
/**
|
||||
@@ -220,11 +220,27 @@ public fun CharSequence.slice(indices: Iterable<Int>): CharSequence {
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a substring specified by the given [range].
|
||||
*/
|
||||
public fun String.substring(range: IntRange): String = substring(range.start, range.end + 1)
|
||||
|
||||
/**
|
||||
* Returns a subsequence of this sequence specified by the given [range].
|
||||
*/
|
||||
public fun CharSequence.subSequence(range: IntRange): CharSequence = subSequence(range.start, range.end + 1)
|
||||
|
||||
public fun CharSequence.substring(start: Int, end: Int = length): String = subSequence(start, end).toString()
|
||||
|
||||
public fun CharSequence.substring(range: IntRange): String = subSequence(range.start, range.end + 1).toString()
|
||||
|
||||
/**
|
||||
* Creates a string from all the elements separated using [separator] and using the given [prefix] and [postfix] if supplied.
|
||||
* If the collection could be huge, you can specify a non-negative value of [limit], in which case only the first [limit]
|
||||
@@ -332,7 +348,7 @@ public fun String.substringAfterLast(delimiter: String, missingDelimiterValue: S
|
||||
* @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.
|
||||
*/
|
||||
public fun String.replaceRange(firstIndex: Int, lastIndex: Int, replacement: String): String {
|
||||
public fun CharSequence.replaceRange(firstIndex: Int, lastIndex: Int, replacement: CharSequence): String {
|
||||
if (lastIndex < firstIndex)
|
||||
throw IndexOutOfBoundsException("Last index ($lastIndex) is less than first index ($firstIndex)")
|
||||
val sb = StringBuilder()
|
||||
@@ -347,7 +363,7 @@ public fun String.replaceRange(firstIndex: Int, lastIndex: Int, replacement: Str
|
||||
*
|
||||
* The end index of the [range] is included in the part to be replaced.
|
||||
*/
|
||||
public fun String.replaceRange(range: IntRange, replacement: String): String = replaceRange(range.start, range.end + 1, replacement)
|
||||
public fun CharSequence.replaceRange(range: IntRange, replacement: CharSequence): String = replaceRange(range.start, range.end + 1, replacement)
|
||||
|
||||
/**
|
||||
* Removes the part of a string at a given range.
|
||||
@@ -356,12 +372,12 @@ public fun String.replaceRange(range: IntRange, replacement: String): String = r
|
||||
*
|
||||
* [lastIndex] is not included in the removed part.
|
||||
*/
|
||||
public fun String.removeRange(firstIndex: Int, lastIndex: Int): String {
|
||||
public fun CharSequence.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
|
||||
return this.toString()
|
||||
|
||||
val sb = StringBuilder(length() - (lastIndex - firstIndex))
|
||||
sb.append(this, 0, firstIndex)
|
||||
@@ -374,7 +390,7 @@ public fun String.removeRange(firstIndex: Int, lastIndex: Int): String {
|
||||
*
|
||||
* The end index of the [range] is included in the removed part.
|
||||
*/
|
||||
public fun String.removeRange(range: IntRange): String = removeRange(range.start, range.end + 1)
|
||||
public fun CharSequence.removeRange(range: IntRange): String = removeRange(range.start, range.end + 1)
|
||||
|
||||
/**
|
||||
* If this string starts with the given [prefix], returns a copy of this string
|
||||
@@ -500,39 +516,39 @@ public fun String.replaceBeforeLast(delimiter: String, replacement: String, miss
|
||||
* 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.
|
||||
*/
|
||||
public fun String.replace(regex: Regex, replacement: String): String = regex.replace(this, replacement)
|
||||
public fun CharSequence.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.
|
||||
*/
|
||||
public fun String.replace(regex: Regex, transform: (MatchResult) -> String): String = regex.replace(this, transform)
|
||||
public fun CharSequence.replace(regex: Regex, transform: (MatchResult) -> CharSequence): 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.
|
||||
*/
|
||||
public fun String.replaceFirst(regex: Regex, replacement: String): String = regex.replaceFirst(this, replacement)
|
||||
public fun CharSequence.replaceFirst(regex: Regex, replacement: String): String = regex.replaceFirst(this, replacement)
|
||||
|
||||
|
||||
/**
|
||||
* Returns `true` if this string matches the given regular expression.
|
||||
*/
|
||||
public fun String.matches(regex: Regex): Boolean = regex.matches(this)
|
||||
public fun CharSequence.matches(regex: Regex): Boolean = regex.matches(this)
|
||||
|
||||
|
||||
/**
|
||||
* Returns `true` if this string starts with the specified character.
|
||||
*/
|
||||
public fun String.startsWith(char: Char, ignoreCase: Boolean = false): Boolean =
|
||||
public fun CharSequence.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.
|
||||
*/
|
||||
public fun String.endsWith(char: Char, ignoreCase: Boolean = false): Boolean =
|
||||
public fun CharSequence.endsWith(char: Char, ignoreCase: Boolean = false): Boolean =
|
||||
this.length() > 0 && this[lastIndex].equals(char, ignoreCase)
|
||||
|
||||
|
||||
@@ -584,8 +600,8 @@ public fun CharSequence.commonSuffixWith(other: CharSequence, ignoreCase: Boolea
|
||||
|
||||
// indexOfAny()
|
||||
|
||||
private fun String.findAnyOf(chars: CharArray, startIndex: Int, ignoreCase: Boolean, last: Boolean): Pair<Int, Char>? {
|
||||
if (!ignoreCase && chars.size() == 1) {
|
||||
private fun CharSequence.findAnyOf(chars: CharArray, startIndex: Int, ignoreCase: Boolean, last: Boolean): Pair<Int, Char>? {
|
||||
if (!ignoreCase && chars.size() == 1 && this is String) {
|
||||
val char = chars.single()
|
||||
val index = if (!last) nativeIndexOf(char, startIndex) else nativeLastIndexOf(char, startIndex)
|
||||
return if (index < 0) null else index to char
|
||||
@@ -610,7 +626,7 @@ private fun String.findAnyOf(chars: CharArray, startIndex: Int, ignoreCase: Bool
|
||||
* @returns An index of the first occurrence of matched character from [chars] or -1 if none of [chars] are found.
|
||||
*
|
||||
*/
|
||||
public fun String.indexOfAny(chars: CharArray, startIndex: Int = 0, ignoreCase: Boolean = false): Int =
|
||||
public fun CharSequence.indexOfAny(chars: CharArray, startIndex: Int = 0, ignoreCase: Boolean = false): Int =
|
||||
findAnyOf(chars, startIndex, ignoreCase, last = false)?.first ?: -1
|
||||
|
||||
/**
|
||||
@@ -622,7 +638,7 @@ public fun String.indexOfAny(chars: CharArray, startIndex: Int = 0, ignoreCase:
|
||||
* @returns An index of the last occurrence of matched character from [chars] or -1 if none of [chars] are found.
|
||||
*
|
||||
*/
|
||||
public fun String.lastIndexOfAny(chars: CharArray, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int =
|
||||
public fun CharSequence.lastIndexOfAny(chars: CharArray, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int =
|
||||
findAnyOf(chars, startIndex, ignoreCase, last = true)?.first ?: -1
|
||||
|
||||
|
||||
@@ -711,8 +727,8 @@ public fun String.lastIndexOfAny(strings: Collection<String>, startIndex: Int =
|
||||
* @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.
|
||||
*/
|
||||
public fun String.indexOf(char: Char, startIndex: Int = 0, ignoreCase: Boolean = false): Int {
|
||||
return if (ignoreCase)
|
||||
public fun CharSequence.indexOf(char: Char, startIndex: Int = 0, ignoreCase: Boolean = false): Int {
|
||||
return if (ignoreCase || this !is String)
|
||||
indexOfAny(charArrayOf(char), startIndex, ignoreCase)
|
||||
else
|
||||
nativeIndexOf(char, startIndex)
|
||||
@@ -724,7 +740,6 @@ public fun String.indexOf(char: Char, startIndex: Int = 0, ignoreCase: Boolean =
|
||||
* @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)
|
||||
@@ -739,8 +754,8 @@ public fun String.indexOf(string: String, startIndex: Int = 0, ignoreCase: Boole
|
||||
* @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.
|
||||
*/
|
||||
public fun String.lastIndexOf(char: Char, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int {
|
||||
return if (ignoreCase)
|
||||
public fun CharSequence.lastIndexOf(char: Char, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int {
|
||||
return if (ignoreCase || this !is String)
|
||||
lastIndexOfAny(charArrayOf(char), startIndex, ignoreCase)
|
||||
else
|
||||
nativeLastIndexOf(char, startIndex)
|
||||
@@ -774,7 +789,7 @@ public operator fun String.contains(seq: CharSequence, ignoreCase: Boolean = fal
|
||||
*
|
||||
* @param ignoreCase `true` to ignore character case when comparing characters. By default `false`.
|
||||
*/
|
||||
public operator fun String.contains(char: Char, ignoreCase: Boolean = false): Boolean =
|
||||
public operator fun CharSequence.contains(char: Char, ignoreCase: Boolean = false): Boolean =
|
||||
indexOf(char, ignoreCase = ignoreCase) >= 0
|
||||
|
||||
/**
|
||||
|
||||
@@ -298,7 +298,7 @@ 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() }
|
||||
public fun CharSequence.isBlank(): Boolean = length() == 0 || indices.all { this[it].isWhitespace() }
|
||||
|
||||
/**
|
||||
* Returns the index within this string that is offset from the given [index] by [codePointOffset] code points.
|
||||
@@ -392,12 +392,7 @@ public fun String.toByteArray(charset: String): ByteArray = (this as java.lang.S
|
||||
*/
|
||||
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
|
||||
@@ -437,7 +432,7 @@ public fun String.repeat(n: Int): String {
|
||||
if (n < 0)
|
||||
throw IllegalArgumentException("Value should be non-negative, but was $n")
|
||||
|
||||
val sb = StringBuilder()
|
||||
val sb = StringBuilder(n * length())
|
||||
for (i in 1..n) {
|
||||
sb.append(this)
|
||||
}
|
||||
@@ -448,7 +443,7 @@ public fun String.repeat(n: Int): String {
|
||||
* Appends the contents of this string, excluding the first characters that satisfy the given [predicate],
|
||||
* to the given Appendable.
|
||||
*/
|
||||
public inline fun <T : Appendable> String.dropWhileTo(result: T, predicate: (Char) -> Boolean): T {
|
||||
public inline fun <T : Appendable> CharSequence.dropWhileTo(result: T, predicate: (Char) -> Boolean): T {
|
||||
var start = true
|
||||
for (element in this) {
|
||||
if (start && predicate(element)) {
|
||||
@@ -464,7 +459,7 @@ public inline fun <T : Appendable> String.dropWhileTo(result: T, predicate: (Cha
|
||||
/**
|
||||
* Appends the first characters from this string that satisfy the given [predicate] to the given Appendable.
|
||||
*/
|
||||
public inline fun <T : Appendable> String.takeWhileTo(result: T, predicate: (Char) -> Boolean): T {
|
||||
public inline fun <T : Appendable> CharSequence.takeWhileTo(result: T, predicate: (Char) -> Boolean): T {
|
||||
for (c in this) if (predicate(c)) result.append(c) else break
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ public class Regex internal constructor(private val nativePattern: Pattern) {
|
||||
* the given function [transform] that takes [MatchResult] and returns a string to be used as a
|
||||
* replacement for that match.
|
||||
*/
|
||||
public inline fun replace(input: CharSequence, transform: (MatchResult) -> String): String {
|
||||
public inline fun replace(input: CharSequence, transform: (MatchResult) -> CharSequence): String {
|
||||
var match: MatchResult? = find(input) ?: return input.toString()
|
||||
|
||||
var lastStart = 0
|
||||
|
||||
Reference in New Issue
Block a user