使用Regex分割Kotlin和Java String之间的区别

Difference between Kotlin and Java String split with Regex

如果我们有一个val txt: kotlin.String ="1;2;3;",并且希望将其拆分为数字数组,则可以尝试以下操作:

1
2
val numbers = string.split(";".toRegex())
//gives: [1, 2, 3, ]

CharSequence.split的结果中包含尾随的空String

另一方面,如果我们查看Java String,则结果是不同的:

1
2
val numbers2 = (string as java.lang.String).split(";")
//gives: [1, 2, 3]

这次,使用java.lang.String.split,结果不包括结尾的空String。实际上,考虑到相应的JavaDoc,此行为是预期的:

This method works as if by invoking the two-argument split method with the given expression and a limit argument of zero. Trailing empty strings are therefore not included in the resulting array.

尽管在Kotlin的版本中,0也是此处记录的默认limit参数,但内部Kotlin在调用java.util.regex.Pattern::split时将0映射为负值-1

1
nativePattern.split(input, if (limit == 0) -1 else limit).asList()

它似乎按预期工作,但我想知道为什么该语言似乎在限制Java API,因为不再提供0限制。


该实现意味着通过传递limit = 0来实现的java.lang.String.split行为在Kotlin中丢失。实际上,从我的angular来看,为了确保Kotlin中可能的选项之间的一致性,已将其删除。

考虑一个字符串a:b:c:d:和一个模式:

看看我们在Java中可以拥有什么:

limit < 0[a, b, c, d, ]
limit = 0[a, b, c, d]
limit = 1[a:b:c:d:]
limit = 2[a, b:c:d:]
limit = 3[a, b, c:d:]
limit = 4[a, b, c, d:]
limit = 5[a, b, c, d, ](与limit < 0相同)
limit = 6[a, b, c, d, ]
...

看来limit = 0选项有些独特:它的尾随:既不被其他条目代替(如limit < 0limit >= 5),也不保留在最后的结果项中(如< 1.25)中的x25>。

在我看来,Kotlin API改善了此处的一致性:在某种意义上,没有特殊情况会丢失有关最后一个定界符的信息,后跟一个空字符串–它保留在最后一个定界符中结果项目或作为尾随的空条目。

IMO,Kotlin功能似乎更符合最小惊讶原则。相反,java.lang.String.split中的零极限看起来更像是修改方法语义的特殊值。负值也是如此,负值显然没有直观意义上的限制,并且如果不深入研究Javadoc,就不太清楚。