在 Kotlin-way 中获取包含在字符串中的子字符串的索引

Rar*_*rap 2 kotlin

我想实现一个函数,该函数将返回指定字符串中子字符串的索引。现在我是用 Java 风格做的:

public fun String?.indexesOf(substr: String, ignoreCase: Boolean = true): List<Int> {
    var list = mutableListOf<Int>()
    if (substr.isNullOrBlank()) return list
    var count = 0;
    this?.split(substr, ignoreCase = ignoreCase)?.forEach {
        count += it.length
        list.add(count)
        count += substr.length
    }
    list.remove(list.get(list.size-1))
    return list
}
Run Code Online (Sandbox Code Playgroud)

但我认为这不是 kotlin 方式的解决方案。它看起来最像典型的 java 程序,但用 kotlin 编写。如何使用 kotlin 更优雅地实现这一点?

Mic*_*ael 7

你可以把它压缩成这样:

public fun String?.indexesOf(substr: String, ignoreCase: Boolean = true): List<Int> {
    return this?.let { 
        val regex = if (ignoreCase) Regex(substr, RegexOption.IGNORE_CASE) else Regex(substr)
        regex.findAll(this).map { it.range.start }.toList()
    } ?: emptyList()
}
Run Code Online (Sandbox Code Playgroud)

这是否更有效是另一回事。你必须测试一下。


如果您想"aaa".indexesOf("aa")返回[0, 1]而不仅仅是[0],您应该能够通过修改正则表达式以使用正向前瞻来实现,即:

val regex = if (ignoreCase) Regex("(?=$substr)", RegexOption.IGNORE_CASE) else Regex("(?=$substr)")
Run Code Online (Sandbox Code Playgroud)


lee*_*ski 6

我会做的是以下内容:

fun ignoreCaseOpt(ignoreCase: Boolean) = 
    if (ignoreCase) setOf(RegexOption.IGNORE_CASE) else emptySet()

fun String?.indexesOf(pat: String, ignoreCase: Boolean = true): List<Int> =
    pat.toRegex(ignoreCaseOpt(ignoreCase))
        .findAll(this?: "")
        .map { it.range.first }
        .toList()

// check:
println("xabcaBd".indexesOf("ab", true))
println("xabcaBd".indexesOf("ab", false))
println("xabcaBd".indexesOf("abx", true))

val s: String? = null
println(s.indexesOf("aaa"))

// output:
[1, 4]
[1]
[]
[]
Run Code Online (Sandbox Code Playgroud)