假设我有一个字符串:
"Hello! How do you do? Good day!"
我想用分隔符?
和 !
来进行切割,使用 "split" 函数的话结果应该是:
`[Hello, How do you do, Good day]`
然而,我希望它是这样的:
`[Hello, !, How do you do, ?, Good day, !]`
这里有一个类似的Java问题:如何拆分一个字符串,同时保留分隔符?
使用前瞻。在Kotlin中,代码可能是这样的:
fun main(args: Array<String>) {
val str = "Hello! How do you do? Good day!"
val reg = Regex("(?<=[!?])|(?=[!?])")
var list = str.split(reg)
println(list)
}
它的输出结果是:
[Hello, !, How do you do, ?, Good day, !]
这是我实现的该函数版本:
fun String.splitKeeping(str: String): List<String> {
return this.split(str).flatMap {listOf(it, str)}.dropLast(1).filterNot {it.isEmpty()}
}
fun String.splitKeeping(vararg strs: String): List<String> {
var res = listOf(this)
strs.forEach {str ->
res = res.flatMap {it.splitKeeping(str)}
}
return res
}
//USAGE:
"Hello! How do you do? Good day!".splitKeeping("!", "?")
虽然它的复杂度是平方级别,但对于相对较短的字符串效果很好。
这里是一个扩展函数,包装了这里讨论的代码:
private const val withDelimiter = "((?<=%1\$s)|(?=%1\$s))"
fun Regex.splitWithDelimiter(input: CharSequence) =
Regex(withDelimiter.format(this.pattern)).split(input)
private fun CharSequence.splitWithDelimiters(delimiter: String, ignoreCase: Boolean = false, limit: Int = 0): List<String> {
require(limit >= 0) { "Limit must be non-negative, but was $limit" }
var currentOffset = 0
var nextIndex = indexOf(delimiter, currentOffset, ignoreCase)
if (nextIndex == -1 || limit == 1) {
return listOf(this.toString())
}
val isLimited = limit > 0
val result = ArrayList<String>(if (isLimited) limit.coerceAtMost(10) else 10)
do {
result.add(substring(currentOffset, nextIndex))
// Adding delimiter(s)
result.add(substring(nextIndex, nextIndex + delimiter.length))
currentOffset = nextIndex + delimiter.length
// Do not search for next occurrence if we're reaching limit
if (isLimited && result.size == limit - 1) break
nextIndex = indexOf(delimiter, currentOffset, ignoreCase)
} while (nextIndex != -1)
result.add(substring(currentOffset, length))
return result
}
\d+
的分割模式来匹配多个数字。 - sschuberth