KT-16661 Simplify Strings#split
Do not search for next occurrence if limit is reached.
This commit is contained in:
@@ -1167,7 +1167,7 @@ public fun CharSequence.split(vararg delimiters: String, ignoreCase: Boolean = f
|
|||||||
if (delimiters.size == 1) {
|
if (delimiters.size == 1) {
|
||||||
val delimiter = delimiters[0]
|
val delimiter = delimiters[0]
|
||||||
if (!delimiter.isEmpty()) {
|
if (!delimiter.isEmpty()) {
|
||||||
return split(delimiters[0], ignoreCase, limit)
|
return split(delimiter, ignoreCase, limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1212,33 +1212,20 @@ private fun CharSequence.split(delimiter: String, ignoreCase: Boolean, limit: In
|
|||||||
|
|
||||||
var currentOffset = 0
|
var currentOffset = 0
|
||||||
var nextIndex = indexOf(delimiter, currentOffset, ignoreCase)
|
var nextIndex = indexOf(delimiter, currentOffset, ignoreCase)
|
||||||
val isLimited = limit > 0
|
if (nextIndex == -1) {
|
||||||
// This condition cannot be moved inside of ctor call because it will kill laziness of internal array allocation
|
|
||||||
val result = if (isLimited) ArrayList<String>(limit.coerceAtMost(10)) else ArrayList<String>()
|
|
||||||
|
|
||||||
while (nextIndex != -1) {
|
|
||||||
if (!isLimited || result.size < limit - 1) {
|
|
||||||
result.add(substring(currentOffset, nextIndex))
|
|
||||||
currentOffset = nextIndex + delimiter.length
|
|
||||||
nextIndex = indexOf(delimiter, currentOffset, ignoreCase)
|
|
||||||
} else {
|
|
||||||
result.add(substring(currentOffset, length))
|
|
||||||
currentOffset = length
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentOffset == 0) {
|
|
||||||
// If no matches found return single element list
|
|
||||||
// instead of triggering allocation of underlying array in 'result'
|
|
||||||
// Speedup is ~15% for small string
|
|
||||||
return listOf(this.toString())
|
return listOf(this.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLimited || result.size < limit) {
|
val isLimited = limit > 0
|
||||||
result.add(substring(currentOffset, length))
|
val result = ArrayList<String>(if (isLimited) limit.coerceAtMost(10) else 10)
|
||||||
|
while (nextIndex != -1 && (!isLimited || result.size < limit - 1)) {
|
||||||
|
result.add(substring(currentOffset, nextIndex))
|
||||||
|
currentOffset = nextIndex + delimiter.length
|
||||||
|
// Do not search for next occurrence if we're reaching limit
|
||||||
|
nextIndex = if (result.size == limit - 1) break else indexOf(delimiter, currentOffset, ignoreCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.add(substring(currentOffset, length))
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -527,12 +527,16 @@ class StringTest {
|
|||||||
assertEquals(listOf("test"), (+"test").split(*arrayOf<String>()), "empty list of delimiters, none matched -> entire string returned")
|
assertEquals(listOf("test"), (+"test").split(*arrayOf<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;def,123;456").split(';', ',', limit = 3))
|
||||||
|
assertEquals(listOf("abc;def,123;456"), (+"abc;def,123;456").split(';', ',', limit = 1))
|
||||||
|
|
||||||
assertEquals(listOf("abc", "def", "123", "456"), (+"abc=-def==123=456").split("==", "=-", "="))
|
assertEquals(listOf("abc", "def", "123", "456"), (+"abc=-def==123=456").split("==", "=-", "="))
|
||||||
|
|
||||||
assertEquals(listOf("", "a", "b", "c", ""), (+"abc").split(""))
|
assertEquals(listOf("", "a", "b", "c", ""), (+"abc").split(""))
|
||||||
assertEquals(listOf("", "a", "b", "b", "a", ""), (+"abba").split("", "a"))
|
assertEquals(listOf("", "a", "b", "b", "a", ""), (+"abba").split("", "a"))
|
||||||
assertEquals(listOf("", "", "b", "b", "", ""), (+"abba").split("a", ""))
|
assertEquals(listOf("", "", "b", "b", "", ""), (+"abba").split("a", ""))
|
||||||
|
assertEquals(listOf("", "bb", ""), (+"abba").split("a", "c"))
|
||||||
|
assertEquals(listOf("", "bb", ""), (+"abba").split('a', 'c'))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun splitSingleDelimiter() = withOneCharSequenceArg { arg1 ->
|
@Test fun splitSingleDelimiter() = withOneCharSequenceArg { arg1 ->
|
||||||
@@ -543,10 +547,21 @@ class StringTest {
|
|||||||
assertEquals(listOf("abc", "def", "123,456"), (+"abc,def,123,456").split(',', limit = 3))
|
assertEquals(listOf("abc", "def", "123,456"), (+"abc,def,123,456").split(',', limit = 3))
|
||||||
assertEquals(listOf("abc", "def", "123,456"), (+"abc,def,123,456").split(",", limit = 3))
|
assertEquals(listOf("abc", "def", "123,456"), (+"abc,def,123,456").split(",", limit = 3))
|
||||||
|
|
||||||
|
assertEquals(listOf("abc", "def", "123,456,789"), (+"abc,def,123,456,789").split(',', limit = 3))
|
||||||
|
assertEquals(listOf("abc", "def", "123,456,789"), (+"abc,def,123,456,789").split(",", limit = 3))
|
||||||
|
|
||||||
|
assertEquals(listOf("abc", "def", "123,456,789,"), (+"abc,def,123,456,789,").split(',', limit = 3))
|
||||||
|
assertEquals(listOf("abc", "def", "123,456,789,"), (+"abc,def,123,456,789,").split(",", limit = 3))
|
||||||
|
|
||||||
|
assertEquals(listOf("abc,def,123,456,789,"), (+"abc,def,123,456,789,").split(',', limit = 1))
|
||||||
|
assertEquals(listOf("abc,def,123,456,789,"), (+"abc,def,123,456,789,").split(",", limit = 1))
|
||||||
|
|
||||||
assertEquals(listOf("abc", "def", "123", "456"), (+"abc<BR>def<br>123<bR>456").split("<BR>", ignoreCase = true))
|
assertEquals(listOf("abc", "def", "123", "456"), (+"abc<BR>def<br>123<bR>456").split("<BR>", ignoreCase = true))
|
||||||
assertEquals(listOf("abc", "def<br>123<bR>456"), (+"abc<BR>def<br>123<bR>456").split("<BR>", ignoreCase = false))
|
assertEquals(listOf("abc", "def<br>123<bR>456"), (+"abc<BR>def<br>123<bR>456").split("<BR>", ignoreCase = false))
|
||||||
|
|
||||||
assertEquals(listOf("a", "b", "c"), (+"a*b*c").split("*"))
|
assertEquals(listOf("a", "b", "c"), (+"a*b*c").split("*"))
|
||||||
|
assertEquals(listOf("", "bb", ""), (+"abba").split("a"))
|
||||||
|
assertEquals(listOf("", "bb", ""), (+"abba").split('a'))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun splitToLines() = withOneCharSequenceArg { arg1 ->
|
@Test fun splitToLines() = withOneCharSequenceArg { arg1 ->
|
||||||
|
|||||||
Reference in New Issue
Block a user