String.split 对于空字符串的行为

问题描述 投票:0回答:3

考虑这种断言模式:

@Test
fun test() {
    val list = listOf("one", "two", "three")
    assertEquals(list.subList(0, 3), list.subList(0, 3).joinToString(" ").split(" "))
    assertEquals(list.subList(0, 2), list.subList(0, 2).joinToString(" ").split(" "))
    assertEquals(list.subList(0, 1), list.subList(0, 1).joinToString(" ").split(" "))
    assertEquals(list.subList(0, 0), list.subList(0, 0).joinToString(" ").split(" "))
}

所有行都遵循列表大小递减的模式。除了最后一个断言有点不一致之外,所有断言都通过了。这是因为

"".split(" ")
不是预期的空列表,而是包含空字符串的单元素列表。

是否有另一种调用

split
或其他函数的方式,其行为符合我如上所述的预期?

kotlin
3个回答
1
投票

作为 lukas.j 答案的细微变化,我认为使用

takeIf()
:

更具可读性
"".split(" ").takeIf { it.size > 1 || it[0].isNotEmpty() } ?: emptyList()

当然你可以将其包装在一个函数中,例如:

fun String.mySplit(separator: String)
    = split(separator)
    .takeIf{ it.size > 1 || it[0].isNotEmpty() }
    ?: emptyList()

(这个例子是一个扩展函数,所以你可以用类似

split()
的方式调用它,例如
"".mySplit(" ")


1
投票

您可以检查 split 返回的列表的大小是否为 1 并且唯一元素是否为空字符串,然后返回一个空列表:

val text = "".split(" ").let { if (it.size == 1 && it[0].isEmpty()) emptyList() else it }

1
投票

这是因为你的第一个示例都是以字符串开头的列表(我不是说

List<String>
,只是它们包含的内容 - 他们在其中得到了一些字符串),所以通过将它们连接成一个字符串并将其拆分出来放入字符串列表中,最终会得到与开始时相同的内容

对于空列表,其中没有字符串,通过调用

joinToString
您可以创建一个列表。
split
作用于字符串并始终返回它们的列表 - 这就是您所期望的,对吗?
"hello".split(" ")
不应该仅仅因为没有空间可以分割而返回空列表,所以也不应该
"".split(" ")
- 你总是只得到你调用它的原始字符串

因此,整个

joinToString -> split
管道会生成一个列表,其中至少包含一个字符串,当您从字符串列表开始时,这很好,但如果您从空列表开始,则不行 - 它并不完全不一致,对于这种边缘情况,逻辑就失败了。如果这是针对某种处理功能(例如处理可能为空的任意
List<String>
),我会考虑明确处理该边缘情况:

fun List<String>.doThing() =
    if (isEmpty()) emptyList() // or just 'this' if that works for you
    else joinToString(" ").split(" ")

或者无论你在做什么!

© www.soinside.com 2019 - 2024. All rights reserved.