为什么空字符串上的“分割”返回一个非空数组?

在空字符串上拆分返回大小为1的数组:

scala> "".split(',')
res1: Array[String] = Array("")

请考虑这将返回空数组:

scala> ",,,,".split(',')
res2: Array[String] = Array()

请解释:)

91095 次浏览

分割空字符串将返回作为第一个元素的空字符串。如果在目标字符串中没有找到分隔符,则将获得一个大小为1的数组,其中包含原始字符串,即使该字符串为空。

在所有的编程语言中,我知道空字符串仍然是有效的字符串。因此,使用任何分隔符进行拆分将始终返回单个元素数组,其中该元素为空 String。如果它是一个 null (非空)字符串,那么这将是一个不同的问题。

出于同样的原因

",test" split ','

还有

",test," split ','

将返回一个大小为2的数组。在第一次匹配之前的所有内容都作为第一个元素返回。

如果你把一个橙子零分开,你只有一块——橙子。

- > "a" 因此 - > ""

Java 和 Scala 拆分方法的操作步骤如下:

  • 首先,按分隔符拆分字符串。自然的结果是,如果字符串不包含分隔符,则返回一个只包含输入字符串的单例数组,
  • 第二,删除所有最右边的空字符串。这就是 ",,,".split(",")返回空数组的原因。

根据这一点,"".split(",")的结果应该是一个空数组,因为第二步,对不对?

应该的。不幸的是,这是一个人为引入的角落情况。这是不好的,但至少它是 java.util.regex.Pattern中的 记录在案,如果你记得看一下文档:

对于 n = = 0,结果与 n < 0相同,只不过后跟的是空字符串 将不会返回。 < strong > (注意,输入本身是一个 空字符串是特殊的,如上所述,并且极限参数 不适用于此。)

解决方案1: 始终传递 -1作为第二个参数

因此,我建议您总是将 n == -1作为第二个参数传递(这将跳过上面的第二步) ,除非您明确知道您想要实现什么/您确信空字符串不是您的程序将获得的输入。

解决方案2: 使用番石榴分割器类

如果您已经在项目中使用了番石榴,可以尝试使用 拆分器(文档)类。它有一个非常丰富的 API,使您的代码非常容易理解。

Splitter.on(".").split(".a.b.c.") // "", "a", "b", "c", ""
Splitter.on(",").omitEmptyStrings().split("a,,b,,c") // "a", "b", "c"
Splitter.on(CharMatcher.anyOf(",.")).split("a,b.c") // "a", "b", "c"
Splitter.onPattern("=>?").split("a=b=>c") // "a", "b", "c"
Splitter.on(",").limit(2).split("a,b,c") // "a", "b,c"

这个 split行为是从 Java 继承来的,不管是好是坏..。
Scala 不会覆盖来自 String原语的定义。

请注意,你可以 使用 limit参数修改行为:

极限参数控制应用模式的次数,因此影响结果数组的长度。如果限制 n 大于零,那么模式最多应用 n-1次,数组的长度不会大于 n,数组的最后一个条目将包含超过最后一个匹配的分隔符的所有输入。如果 n 是非正的,那么模式将被应用尽可能多次,并且数组可以有任意长度。如果 n 为零,那么模式将被应用尽可能多次,数组可以有任意长度,并且尾随的空字符串将被丢弃。

例如,您可以设置 limit=-1来获得(所有?)其他语言的行为:

@ ",a,,b,,".split(",")
res1: Array[String] = Array("", "a", "", "b")


@ ",a,,b,,".split(",", -1)  // limit=-1
res2: Array[String] = Array("", "a", "", "b", "", "")

众所周知,Java 的行为是 很困惑,但是:

至少从 Java5到 Java8都可以观察到上述行为。

JDK-6559590中分割空字符串时,尝试更改行为以返回空数组。然而,当它在不同的地方引起消退时,它很快在 JDK-8028321中恢复。这个更改从未进入最初的 Java8版本。

注意: Split 方法从一开始就不在 Java 中(它是 不是在1.0。2) ,但实际上至少从1.4开始就存在(例如,参见 JSR51 circa 2002)。我还在调查..。

不清楚的是 Java 最初为什么选择这种方式(我怀疑它最初是“边缘情况”中的一个疏忽/bug) ,但是现在已经不可逆转地融入到了语言中,因此也融入到了 还在中。

空字符串在拆分字符串时没有特殊状态。您可以使用:

Some(str)
.filter(_ != "")
.map(_.split(","))
.getOrElse(Array())

使用这个函数,

public static ArrayList<String> split(String body) {
return new ArrayList<>(Arrays.asList(Optional.ofNullable(body).filter(a->!a.isEmpty()).orElse(",").split(",")));
}