Generalize String extensions to take CharSequence as receiver and parameters where applicable.

This commit is contained in:
Ilya Gorbunov
2015-10-12 05:54:08 +03:00
parent 05615dd48b
commit 4a621cbb5f
5 changed files with 65 additions and 57 deletions
+1 -1
View File
@@ -109,7 +109,7 @@ public class Regex(pattern: String, options: Set<RegexOption>) {
* 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 = match(input)
if (match == null) return input.toString()
+1 -3
View File
@@ -43,9 +43,7 @@ public inline fun String.matches(regex : String) : Boolean {
return result != null && result.size() > 0
}
public inline fun CharSequence.isEmpty(): Boolean = this.length() == 0
public fun String.isBlank(): Boolean = length() == 0 || matches("^[\\s\\xA0]+$")
public fun CharSequence.isBlank(): Boolean = length() == 0 || (if (this is String) this else this.toString()).matches("^[\\s\\xA0]+$")
public fun String?.equals(anotherString: String?, ignoreCase: Boolean = false): Boolean =
if (this == null)
+57 -42
View File
@@ -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
/**
+5 -10
View File
@@ -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