Add methods for String: indexOfAny, lastIndexOfAny, indexOf, lastIndexOf, rangesDelimitedBy, splitToSequence, split, lineSequence, lines.

Add methods for Char: toUpperCase, toLowerCase.
Add an optional boolean parameter ignoreCase to the methods Char.equals, String.equals, String.startsWith, String.endsWith, String.contains.
This commit is contained in:
Ilya Gorbunov
2015-03-24 21:03:49 +03:00
committed by Ilya Gorbunov
parent e9e8be5b4e
commit 6f7a4d8429
5 changed files with 590 additions and 70 deletions
+19
View File
@@ -20,3 +20,22 @@ package kotlin
* Concatenates this Char and a String
*/
public fun Char.plus(string: String) : String = this.toString() + string
/**
* Returns `true` if this character is equal to the [other] character, optionally ignoring character case.
*
* @param ignoreCase `true` to ignore character case when comparing characters. By default `false`.
*
* Two characters are considered the same ignoring case if at least one of the following is true:
* - The two characters are the same (as compared by the == operator)
* - Applying the method [toUpperCase] to each character produces the same result
* - Applying the method [toLowerCase] to each character produces the same result
*/
public fun Char.equals(other: Char, ignoreCase: Boolean = false): Boolean {
if (this === other) return true
if (!ignoreCase) return false
if (this.toUpperCase() === other.toUpperCase()) return true
if (this.toLowerCase() === other.toLowerCase()) return true
return false
}
@@ -73,3 +73,13 @@ public fun Char.isUpperCase(): Boolean = Character.isUpperCase(this)
* Returns `true` if this character is lower case.
*/
public fun Char.isLowerCase(): Boolean = Character.isLowerCase(this)
/**
* Converts this character to uppercase.
*/
public fun Char.toUpperCase(): Char = Character.toUpperCase(this)
/**
* Converts this character to lowercase.
*/
public fun Char.toLowerCase(): Char = Character.toLowerCase(this)
+330
View File
@@ -1,5 +1,7 @@
package kotlin
import java.util.NoSuchElementException
/** Returns the string with leading and trailing text matching the given string removed */
deprecated("Use removeEnclosing(text, text) or removePrefix(text).removeSuffix(text)")
public fun String.trim(text: String): String = removePrefix(text).removeSuffix(text)
@@ -462,3 +464,331 @@ public fun String.replaceBeforeLast(delimiter: String, replacement: String, miss
val index = lastIndexOf(delimiter)
return if (index == -1) missingDelimiterValue else replaceRange(0, index, replacement)
}
/**
* Returns `true` if this string starts with the specified character.
*/
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.
*/
public fun String.endsWith(char: Char, ignoreCase: Boolean = false): Boolean =
this.length() > 0 && this[lastIndex].equals(char, ignoreCase)
// indexOfAny()
private fun String.indexOfAny(chars: CharArray, startIndex: Int, ignoreCase: Boolean, last: Boolean): Pair<Int, Char>? {
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 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 A pair of an index of the first occurrence of matched character from [chars] and the character matched or `null` if none of [chars] are found.
*
*/
public fun String.indexOfAny(chars: CharArray, startIndex: Int = 0, ignoreCase: Boolean = false): Pair<Int, Char>? =
indexOfAny(chars, startIndex, ignoreCase, last = false)
/**
* Finds 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 A pair of an index of the last occurrence of matched character from [chars] and the character matched or `null` if none of [chars] are found.
*
*/
public fun String.lastIndexOfAny(chars: CharArray, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Pair<Int, Char>? =
indexOfAny(chars, startIndex, ignoreCase, last = true)
private fun String.indexOfAny(strings: Collection<String>, startIndex: Int, ignoreCase: Boolean, last: Boolean): Pair<Int, String>? {
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)..lastIndex 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 [stromgs] 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.indexOfAny(strings: Collection<String>, startIndex: Int = 0, ignoreCase: Boolean = false): Pair<Int, String>? =
indexOfAny(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.lastIndexOfAny(strings: Collection<String>, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Pair<Int, String>? =
indexOfAny(strings, startIndex, ignoreCase, last = true)
// 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.
*/
public fun String.indexOf(char: Char, startIndex: Int = 0, ignoreCase: Boolean = false): Int {
return if (ignoreCase)
indexOfAny(charArray(char), startIndex, ignoreCase)?.first ?: -1
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.
*/
public fun String.indexOf(string: String, startIndex: Int = 0, ignoreCase: Boolean = false): Int {
return if (ignoreCase)
indexOfAny(listOf(string), startIndex, ignoreCase)?.first ?: -1
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.
*/
public fun String.lastIndexOf(char: Char, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int {
return if (ignoreCase)
lastIndexOfAny(charArray(char), startIndex, ignoreCase)?.first ?: -1
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)?.first ?: -1
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 fun String.contains(seq: CharSequence, ignoreCase: Boolean = false): Boolean =
indexOf(seq.toString(), 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<Int, Int>?): Sequence<IntRange> {
override fun iterator(): Iterator<IntRange> = object : Iterator<IntRange> {
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 nextItem: IntRange? = null
var counter: Int = 0
private fun calcNext() {
if (currentStartIndex < 0) {
nextState = 0
nextItem = null
}
else {
if (limit > 0 && ++counter >= limit) {
nextItem = currentStartIndex..string.lastIndex
currentStartIndex = -1
}
else {
val match = string.getNextMatch(currentStartIndex)
if (match == null) {
nextItem = currentStartIndex..string.lastIndex
currentStartIndex = -1
}
else {
val (index,length) = match
nextItem = currentStartIndex..index-1
currentStartIndex = index + length
}
}
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<IntRange> {
require(limit >= 0, { "Limit must be non-negative, but was $limit" })
return DelimitedRangesSequence(this, startIndex, limit, { startIndex -> indexOfAny(delimiters, startIndex, ignoreCase = ignoreCase)?.let { Pair(it.first, 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<IntRange> {
require(limit >= 0, { "Limit must be non-negative, but was $limit" } )
val delimitersList = delimiters.asList()
return DelimitedRangesSequence(this, startIndex, limit, { startIndex -> indexOfAny(delimitersList, startIndex, ignoreCase = ignoreCase)?.let { Pair(it.first, 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<String> =
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<String> =
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<String> =
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<String> =
splitToSequence(*delimiters, ignoreCase = ignoreCase, limit = limit).toList()
/**
* 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<String> = 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<String> = lineSequence().toList()
+57 -64
View File
@@ -7,35 +7,50 @@ import java.util.regex.MatchResult
import java.util.regex.Pattern
import java.nio.charset.Charset
/**
* Returns the index within this string of the last occurrence of the specified substring.
* Returns the index within this string of the first occurrence of the specified character, starting from the specified offset.
*/
public fun String.lastIndexOf(str: String): Int = (this as java.lang.String).lastIndexOf(str)
private fun String.nativeIndexOf(ch: Char, fromIndex: Int): Int = (this as java.lang.String).indexOf(ch.toInt(), fromIndex)
/**
* Returns the index within this string of the first occurrence of the specified substring, starting from the specified offset.
*/
private fun String.nativeIndexOf(str: String, fromIndex: Int): Int = (this as java.lang.String).indexOf(str, fromIndex)
/**
* Returns the index within this string of the last occurrence of the specified character.
*/
public fun String.lastIndexOf(ch: Char): Int = (this as java.lang.String).lastIndexOf(ch.toString())
private fun String.nativeLastIndexOf(ch: Char, fromIndex: Int): Int = (this as java.lang.String).lastIndexOf(ch.toInt(), fromIndex)
/**
* Returns the index within this string of the last occurrence of the specified character, starting from the specified offset.
*/
private fun String.nativeLastIndexOf(str: String, fromIndex: Int): Int = (this as java.lang.String).lastIndexOf(str, fromIndex)
/**
* Compares this string to another string, ignoring case considerations.
*/
public fun String.equalsIgnoreCase(anotherString: String): Boolean = (this as java.lang.String).equalsIgnoreCase(anotherString)
deprecated("Use equals(anotherString, ignoreCase = true) instead")
public fun String.equalsIgnoreCase(anotherString: String): Boolean = equals(anotherString, ignoreCase = true)
/**
* 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 =
if (!ignoreCase)
(this as java.lang.String).equals(anotherString)
else
(this as java.lang.String).equalsIgnoreCase(anotherString)
/**
* Returns the hash code of this string.
*/
public fun String.hashCode(): Int = (this as java.lang.String).hashCode()
/**
* Returns the index within this string of the first occurrence of the specified substring.
*/
public fun String.indexOf(str: String): Int = (this as java.lang.String).indexOf(str)
/**
* Returns the index within this string of the first occurrence of the specified substring, starting from the specified offset.
*/
public fun String.indexOf(str: String, fromIndex: Int): Int = (this as java.lang.String).indexOf(str, fromIndex)
/**
* Returns a copy of this string with all occurrences of [oldChar] replaced with [newChar].
@@ -78,12 +93,8 @@ public fun String.format(locale: Locale, vararg args : Any?) : String = java.lan
/**
* Splits this string around matches of the given regular expression.
*/
public fun String.split(regex: String): Array<String> = (this as java.lang.String).split(regex)
public fun String.split(regex: Pattern, limit: Int = 0): List<String> = regex.split(this, limit).asList()
/**
* Splits this string around occurrences of the specified character.
*/
public fun String.split(ch: Char): Array<String> = (this as java.lang.String).split(java.util.regex.Pattern.quote(ch.toString()))
/**
* Returns a substring of this string starting with the specified index.
@@ -98,32 +109,32 @@ public fun String.substring(beginIndex: Int, endIndex: Int): String = (this as j
/**
* Returns `true` if this string starts with the specified prefix.
*/
public fun String.startsWith(prefix: String): Boolean = (this as java.lang.String).startsWith(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 subsring of this string starting at the specified offset starts with the specified prefix.
* 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, toffset: Int): Boolean = (this as java.lang.String).startsWith(prefix, toffset)
/**
* Returns `true` if this string starts with the specified character.
*/
public fun String.startsWith(ch: Char): Boolean = (this as java.lang.String).startsWith(ch.toString())
/**
* Returns `true` if this string contains the specified sequence of characters as a substring.
*/
public fun String.contains(seq: CharSequence): Boolean = (this as java.lang.String).contains(seq)
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): Boolean = (this as java.lang.String).endsWith(suffix)
/**
* Returns `true` if this string ends with the specified character.
*/
public fun String.endsWith(ch: Char): Boolean = (this as java.lang.String).endsWith(ch.toString())
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
@@ -207,11 +218,6 @@ public fun String(stringBuilder: java.lang.StringBuilder): String = java.lang.St
*/
public fun String.replaceFirst(regex: String, replacement: String): String = (this as java.lang.String).replaceFirst(regex, replacement)
/**
* Splits this string into at most [limit] chunks around matches of the given regular expression.
*/
public fun String.split(regex: String, limit: Int): Array<String> = (this as java.lang.String).split(regex, limit)
/**
* Returns the character (Unicode code point) at the specified index.
*/
@@ -256,15 +262,6 @@ public fun String.contentEquals(sb: StringBuffer): Boolean = (this as java.lang.
*/
public fun String.getChars(srcBegin: Int, srcEnd: Int, dst: CharArray, dstBegin: Int): Unit = (this as java.lang.String).getChars(srcBegin, srcEnd, dst, dstBegin)
/**
* Returns the index within this string of the first occurrence of the specified character.
*/
public fun String.indexOf(ch: Char): Int = (this as java.lang.String).indexOf(ch.toString())
/**
* Returns the index within this string of the first occurrence of the specified character, starting from the specified offset.
*/
public fun String.indexOf(ch: Char, fromIndex: Int): Int = (this as java.lang.String).indexOf(ch.toString(), fromIndex)
/**
* Returns a canonical representation for this string object.
@@ -276,15 +273,6 @@ public fun String.intern(): String = (this as java.lang.String).intern()
*/
public fun String.isEmpty(): Boolean = (this as java.lang.String).isEmpty()
/**
* Returns the index within this string of the last occurrence of the specified character.
*/
public fun String.lastIndexOf(ch: Char, fromIndex: Int): Int = (this as java.lang.String).lastIndexOf(ch.toString(), fromIndex)
/**
* Returns the index within this string of the last occurrence of the specified character, starting from the specified offset.
*/
public fun String.lastIndexOf(str: String, fromIndex: Int): Int = (this as java.lang.String).lastIndexOf(str, fromIndex)
/**
* Returns `true` if this string matches the given regular expression.
@@ -304,16 +292,21 @@ public fun String.offsetByCodePoints(index: Int, codePointOffset: Int): Int = (t
* @param ooffset the start offset in the other string of the substring to compare.
* @param len the length of the substring to compare.
*/
deprecated("Use regionMatches overload with ignoreCase as optional last parameter.")
public fun String.regionMatches(ignoreCase: Boolean, toffset: Int, other: String, ooffset: Int, len: Int): Boolean = (this as java.lang.String).regionMatches(ignoreCase, toffset, other, ooffset, len)
/**
* Returns `true` if the specified range in this string is equal to the specified range in another string.
* @param toffset the start offset in this string of the substring to compare.
* @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 ooffset the start offset in the other string of the substring to compare.
* @param len the length of the substring to compare.
* @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(toffset: Int, other: String, ooffset: Int, len: Int): Boolean = (this as java.lang.String).regionMatches(toffset, other, ooffset, len)
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 new string obtained by replacing all occurrences of the [target] substring in this string
+174 -6
View File
@@ -5,31 +5,40 @@ import org.junit.Test as test
class StringTest {
test fun startsWith() {
test fun startsWithString() {
assertTrue("abcd".startsWith("ab"))
assertTrue("abcd".startsWith("abcd"))
assertTrue("abcd".startsWith("a"))
assertFalse("abcd".startsWith("abcde"))
assertFalse("abcd".startsWith("b"))
assertFalse("".startsWith('a'))
assertFalse("".startsWith("a"))
assertTrue("some".startsWith(""))
assertTrue("".startsWith(""))
assertTrue("abcd".startsWith("aB", ignoreCase = true))
}
test fun endsWith() {
test fun endsWithString() {
assertTrue("abcd".endsWith("d"))
assertTrue("abcd".endsWith("abcd"))
assertFalse("abcd".endsWith("b"))
assertFalse("".endsWith('a'))
assertTrue("strö".endsWith("", ignoreCase = true))
assertFalse("".endsWith("a"))
assertTrue("some".endsWith(""))
assertTrue("".endsWith(""))
}
test fun testStartsWithChar() {
test fun startsWithChar() {
assertTrue("abcd".startsWith('a'))
assertFalse("abcd".startsWith('b'))
assertTrue("abcd".startsWith('A', ignoreCase = true))
assertFalse("".startsWith('a'))
}
test fun testEndsWithChar() {
test fun endsWithChar() {
assertTrue("abcd".endsWith('d'))
assertFalse("abcd".endsWith('b'))
assertTrue("strö".endsWith('Ö', ignoreCase = true))
assertFalse("".endsWith('a'))
}
@@ -264,4 +273,163 @@ class StringTest {
assertEquals("value", "value".removeSurrounding("<", ">"))
}
/*
// unit test commented out until rangesDelimitiedBy would become public
test fun rangesDelimitedBy() {
assertEquals(listOf(0..2, 4..3, 5..7), "abc--def".rangesDelimitedBy('-').toList())
assertEquals(listOf(0..2, 5..7, 9..10), "abc--def-xy".rangesDelimitedBy("--", "-").toList())
assertEquals(listOf(0..2, 7..9, 14..16), "123<br>456<BR>789".rangesDelimitedBy("<br>", ignoreCase = true).toList())
assertEquals(listOf(2..2, 4..6), "a=b=c=d".rangesDelimitedBy("=", startIndex = 2, limit = 2).toList())
val s = "sample"
assertEquals(listOf(s.indices), s.rangesDelimitedBy("-").toList())
assertEquals(listOf(s.indices), s.rangesDelimitedBy("-", startIndex = -1).toList())
assertTrue(s.rangesDelimitedBy("-", startIndex = s.length()).single().isEmpty())
}
*/
test fun split() {
assertEquals(listOf(""), "".split(";"))
assertEquals(listOf("test"), "test".split(*charArray()), "empty list of delimiters, none matched -> entire string returned")
assertEquals(listOf("test"), "test".split(*array<String>()), "empty list of delimiters, none matched -> entire string returned")
assertEquals(listOf("abc", "def", "123;456"), "abc;def,123;456".split(';', ',', limit = 3))
assertEquals(listOf("abc", "def", "123", "456"), "abc<BR>def<br>123<bR>456".split("<BR>", ignoreCase = true))
assertEquals(listOf("abc", "def", "123", "456"), "abc=-def==123=456".split("==", "=-", "="))
}
test fun splitToLines() {
val string = "first line\rsecond line\nthird line\r\nlast line"
assertEquals(listOf("first line", "second line", "third line", "last line"), string.lines())
val singleLine = "single line"
assertEquals(listOf(singleLine), singleLine.lines())
}
test fun indexOfAnyChar() {
val string = "abracadabra"
val chars = charArray('d','b')
assertEquals(1 to 'b', string.indexOfAny(chars))
assertEquals(6 to 'd', string.indexOfAny(chars, startIndex = 2))
assertEquals(null, string.indexOfAny(chars, startIndex = 9))
assertEquals(8 to 'b', string.lastIndexOfAny(chars))
assertEquals(6 to 'd', string.lastIndexOfAny(chars, startIndex = 7))
assertEquals(null, string.lastIndexOfAny(chars, startIndex = 0))
assertEquals(null, string.indexOfAny(charArray()))
}
test fun indexOfAnyCharIgnoreCase() {
val string = "abraCadabra"
val chars = charArray('B','c')
assertEquals(1 to 'B', string.indexOfAny(chars, ignoreCase = true))
assertEquals(4 to 'c', string.indexOfAny(chars, startIndex = 2, ignoreCase = true))
assertEquals(null, string.indexOfAny(chars, startIndex = 9, ignoreCase = true))
assertEquals(8 to 'B', string.lastIndexOfAny(chars, ignoreCase = true))
assertEquals(4 to 'c', string.lastIndexOfAny(chars, startIndex = 7, ignoreCase = true))
assertEquals(null, string.lastIndexOfAny(chars, startIndex = 0, ignoreCase = true))
}
test fun indexOfAnyString() {
val string = "abracadabra"
val substrings = listOf("rac", "ra")
assertEquals(2 to "rac", string.indexOfAny(substrings))
assertEquals(9 to "ra", string.indexOfAny(substrings, startIndex = 3))
assertEquals(2 to "ra", string.indexOfAny(substrings.reverse()))
assertEquals(null, string.indexOfAny(substrings, 10))
assertEquals(9 to "ra", string.lastIndexOfAny(substrings))
assertEquals(2 to "rac", string.lastIndexOfAny(substrings, startIndex = 8))
assertEquals(2 to "ra", string.lastIndexOfAny(substrings.reverse(), startIndex = 8))
assertEquals(null, string.lastIndexOfAny(substrings, 1))
assertEquals(0 to "", string.indexOfAny(listOf("dab", "")), "empty strings are not ignored")
assertEquals(null, string.indexOfAny(listOf()))
}
test fun indexOfAnyStringIgnoreCase() {
val string = "aBraCadaBrA"
val substrings = listOf("rAc", "Ra")
assertEquals(2 to substrings[0], string.indexOfAny(substrings, ignoreCase = true))
assertEquals(9 to substrings[1], string.indexOfAny(substrings, startIndex = 3, ignoreCase = true))
assertEquals(null, string.indexOfAny(substrings, startIndex = 10, ignoreCase = true))
assertEquals(9 to substrings[1], string.lastIndexOfAny(substrings, ignoreCase = true))
assertEquals(2 to substrings[0], string.lastIndexOfAny(substrings, startIndex = 8, ignoreCase = true))
assertEquals(null, string.lastIndexOfAny(substrings, startIndex = 1, ignoreCase = true))
}
test fun indexOfChar() {
val string = "bcedef"
assertEquals(-1, string.indexOf('a'))
assertEquals(2, string.indexOf('e'))
assertEquals(2, string.indexOf('e', 2))
assertEquals(4, string.indexOf('e', 3))
assertEquals(4, string.lastIndexOf('e'))
assertEquals(2, string.lastIndexOf('e', 3))
for (startIndex in -1..string.length()+1) {
assertEquals(string.indexOfAny(charArray('e'), startIndex)?.first ?: -1, string.indexOf('e', startIndex))
assertEquals(string.lastIndexOfAny(charArray('e'), startIndex)?.first ?: -1, string.lastIndexOf('e', startIndex))
}
}
test fun indexOfCharIgnoreCase() {
val string = "bCEdef"
assertEquals(-1, string.indexOf('a', ignoreCase = true))
assertEquals(2, string.indexOf('E', ignoreCase = true))
assertEquals(2, string.indexOf('e', 2, ignoreCase = true))
assertEquals(4, string.indexOf('E', 3, ignoreCase = true))
assertEquals(4, string.lastIndexOf('E', ignoreCase = true))
assertEquals(2, string.lastIndexOf('e', 3, ignoreCase = true))
for (startIndex in -1..string.length()+1){
assertEquals(string.indexOfAny(charArray('e'), startIndex, ignoreCase = true)?.first ?: -1, string.indexOf('E', startIndex, ignoreCase = true))
assertEquals(string.lastIndexOfAny(charArray('E'), startIndex, ignoreCase = true)?.first ?: -1, string.lastIndexOf('e', startIndex, ignoreCase = true))
}
}
test fun indexOfString() {
val string = "bceded"
for (index in string.indices)
assertEquals(index, string.indexOf("", index))
assertEquals(1, string.indexOf("ced"))
assertEquals(4, string.indexOf("ed", 3))
assertEquals(-1, string.indexOf("abcdefgh"))
}
test fun indexOfStringIgnoreCase() {
val string = "bceded"
for (index in string.indices)
assertEquals(index, string.indexOf("", index, ignoreCase = true))
assertEquals(1, string.indexOf("cEd", ignoreCase = true))
assertEquals(4, string.indexOf("Ed", 3, ignoreCase = true))
assertEquals(-1, string.indexOf("abcdefgh", ignoreCase = true))
}
test fun contains() {
assertTrue("sample".contains("pl"))
assertFalse("sample".contains("PL"))
assertTrue("sömple".contains("Ö", ignoreCase = true))
assertTrue("sample".contains(""))
assertTrue("".contains(""))
}
test fun equalsIgnoreCase() {
assertFalse("sample".equals("Sample", ignoreCase = false))
assertTrue("sample".equals("Sample", ignoreCase = true))
}
}