Use CharSequence in split, splitToSequence, lines

This commit is contained in:
Ilya Gorbunov
2015-10-27 19:14:24 +03:00
parent 8c5ac26613
commit 64338e896d
2 changed files with 29 additions and 121 deletions
+19 -19
View File
@@ -873,11 +873,11 @@ public operator fun CharSequence.contains(regex: Regex): Boolean = regex.contain
// 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> {
private class DelimitedRangesSequence(private val input: CharSequence, private val startIndex: Int, private val limit: Int, private val getNextMatch: CharSequence.(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 currentStartIndex: Int = Math.min(Math.max(startIndex, 0), input.length())
var nextSearchIndex: Int = currentStartIndex
var nextItem: IntRange? = null
var counter: Int = 0
@@ -888,14 +888,14 @@ private class DelimitedRangesSequence(private val string: String, private val st
nextItem = null
}
else {
if (limit > 0 && ++counter >= limit || nextSearchIndex > string.length()) {
nextItem = currentStartIndex..string.lastIndex
if (limit > 0 && ++counter >= limit || nextSearchIndex > input.length()) {
nextItem = currentStartIndex..input.lastIndex
nextSearchIndex = -1
}
else {
val match = string.getNextMatch(nextSearchIndex)
val match = input.getNextMatch(nextSearchIndex)
if (match == null) {
nextItem = currentStartIndex..string.lastIndex
nextItem = currentStartIndex..input.lastIndex
nextSearchIndex = -1
}
else {
@@ -939,7 +939,7 @@ private class DelimitedRangesSequence(private val string: String, private val st
* @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> {
private fun CharSequence.rangesDelimitedBy(delimiters: CharArray, 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 -> findAnyOf(delimiters, startIndex, ignoreCase = ignoreCase, last = false)?.let { it.first to 1 } })
@@ -960,7 +960,7 @@ private fun String.rangesDelimitedBy(vararg delimiters: Char, startIndex: Int =
* 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> {
private fun CharSequence.rangesDelimitedBy(delimiters: Array<out 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()
@@ -982,8 +982,8 @@ private fun String.rangesDelimitedBy(vararg delimiters: String, startIndex: Int
* 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) }
public fun CharSequence.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].
@@ -996,8 +996,8 @@ public fun String.splitToSequence(vararg delimiters: String, ignoreCase: Boolean
* 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()
public fun CharSequence.split(vararg delimiters: String, ignoreCase: Boolean = false, limit: Int = 0): List<String> =
rangesDelimitedBy(delimiters, ignoreCase = ignoreCase, limit = limit).asIterable().map { substring(it) }
/**
* Splits this string to a sequence of strings around occurrences of the specified [delimiters].
@@ -1006,8 +1006,8 @@ public fun String.split(vararg delimiters: String, ignoreCase: Boolean = false,
* @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) }
public fun CharSequence.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].
@@ -1016,8 +1016,8 @@ public fun String.splitToSequence(vararg delimiters: Char, ignoreCase: Boolean =
* @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()
public fun CharSequence.split(vararg delimiters: Char, ignoreCase: Boolean = false, limit: Int = 0): List<String> =
rangesDelimitedBy(delimiters, ignoreCase = ignoreCase, limit = limit).asIterable().map { substring(it) }
/**
* Splits this string around matches of the given regular expression.
@@ -1025,14 +1025,14 @@ public fun String.split(vararg delimiters: Char, ignoreCase: Boolean = false, li
* @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<String> = pattern.split(this, limit)
public fun CharSequence.split(pattern: Regex, limit: Int = 0): List<String> = 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<String> = splitToSequence("\r\n", "\n", "\r")
public fun CharSequence.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()
public fun CharSequence.lines(): List<String> = lineSequence().toList()
@@ -670,104 +670,6 @@ public operator fun String.contains(char: Char, ignoreCase: Boolean = false): Bo
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<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 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<IntRange> {
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<IntRange> {
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
@@ -783,8 +685,9 @@ private fun String.rangesDelimitedBy(vararg delimiters: String, startIndex: Int
* 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.
*/
@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN)
public fun String.splitToSequence(vararg delimiters: String, ignoreCase: Boolean = false, limit: Int = 0): Sequence<String> =
rangesDelimitedBy(*delimiters, ignoreCase = ignoreCase, limit = limit) map { substring(it) }
splitToSequence(*delimiters, ignoreCase = ignoreCase, limit = limit)
/**
* Splits this string to a list of strings around occurrences of the specified [delimiters].
@@ -797,6 +700,7 @@ public fun String.splitToSequence(vararg delimiters: String, ignoreCase: Boolean
* 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.
*/
@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN)
public fun String.split(vararg delimiters: String, ignoreCase: Boolean = false, limit: Int = 0): List<String> =
splitToSequence(*delimiters, ignoreCase = ignoreCase, limit = limit).toList()
@@ -807,8 +711,9 @@ public fun String.split(vararg delimiters: String, ignoreCase: Boolean = false,
* @param ignoreCase `true` to ignore character case when matching a delimiter. By default `false`.
* @param limit The maximum number of substrings to return.
*/
@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN)
public fun String.splitToSequence(vararg delimiters: Char, ignoreCase: Boolean = false, limit: Int = 0): Sequence<String> =
rangesDelimitedBy(*delimiters, ignoreCase = ignoreCase, limit = limit) map { substring(it) }
splitToSequence(*delimiters, ignoreCase = ignoreCase, limit = limit)
/**
* Splits this string to a list of strings around occurrences of the specified [delimiters].
@@ -817,6 +722,7 @@ public fun String.splitToSequence(vararg delimiters: Char, ignoreCase: Boolean =
* @param ignoreCase `true` to ignore character case when matching a delimiter. By default `false`.
* @param limit The maximum number of substrings to return.
*/
@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN)
public fun String.split(vararg delimiters: Char, ignoreCase: Boolean = false, limit: Int = 0): List<String> =
splitToSequence(*delimiters, ignoreCase = ignoreCase, limit = limit).toList()
@@ -826,16 +732,18 @@ public fun String.split(vararg delimiters: Char, ignoreCase: Boolean = false, li
* @param limit Non-negative value specifying the maximum number of substrings to return.
* Zero by default means no limit is set.
*/
@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN)
public fun String.split(pattern: Regex, limit: Int = 0): List<String> = 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<String> = splitToSequence("\r\n", "\n", "\r")
@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN)
public fun String.lineSequence(): Sequence<String> = lineSequence()
/**
* * Splits this string to a list of lines delimited by any of the following character sequences: CRLF, LF or CR.
*/
@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN)
public fun String.lines(): List<String> = lineSequence().toList()
*/