【问题标题】:Why does "split" on an empty string return a non-empty array?为什么空字符串上的“拆分”会返回非空数组?
【发布时间】:2011-06-25 06:27:56
【问题描述】:

对空字符串进行拆分返回大小为 1 的数组:

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

考虑这会返回空数组:

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

请解释一下:)

【问题讨论】:

  • 此外,当字符串仅包含一个分隔符实例时,它似乎与观察到的行为不一致。在这种情况下,结果实际上是一个空数组: ",".split(",").length == 0

标签: java scala


【解决方案1】:

如果你把一个橙子分成零次,你就只有一个——橙子。

【讨论】:

  • 但是橙色不是空的(如果这就是 oluies 的意思,idk),它是一个橙色。也许分割一个应该存在但不存在的橙色,所以你会得到一个值:一个空白空间 xD
  • 这是一次深入的对话。
  • 这个比喻对"orange".split(',') 是有意义的,但显然与拆分空字符串无关。如果我将缺少的橙色零次拆分,我仍然没有橙色;我们是否将其表示为一个空的无橙子列表、一个只有一个无橙子的列表、一个十二个无橙子的列表,还是什么?这不是我们最终得到什么的问题,而是我们如何表现它的问题。
  • 但是如果你将一本不存在的书按页数拆分,你将一无所获。
  • 嗯...0/0 是什么?
【解决方案2】:

Java 和 Scala 的拆分方法分两步操作,如下所示:

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

按照这个,"".split(",")的结果应该是一个空数组,因为第二步吧?

应该。不幸的是,这是一个人为引入的极端案例。这很糟糕,但至少它记录在java.util.regex.Pattern,如果你记得看一下文档:

对于 n == 0,结果与 n (请注意,输入本身就是一个 空字符串是特殊的,如上所述,还有limit参数 不适用于那里。)

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

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

解决方案 2:使用 Guava Splitter 类

如果您已经在项目中使用 Guava,可以尝试 Splitter (documentation) 类。它有一个非常丰富的 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"

【讨论】:

  • +1,这是唯一实际引用文档并指出它不一致的答案。但是,我没有在我的 JavaDoc 中找到注释中突出显示的部分。
  • 我在 java.util.regex.Pattern 中找到了它,但它似乎大部分都消失了。在撰写本文时,它肯定作为 javadoc 存在于官方 OpenJDK 源代码树中。 android.googlesource.com/platform/libcore/+/… 也许我们应该报告一个错误?
  • 报告错误是个好主意 - 行为肯定不会改变,但至少应该记录在案。
  • @RokKralj Android 没有使用 OpenJDK 库,而是基于 Apache Harmony,所以也许你找错地方了?
  • "".split (",", n) 使用 Oracle JDK 8 为 (-1, 0, 1) 中的 n 生成一个元素数组。如果只获得非空标记的列表就好了——猜一个完整的可能需要正则表达式(类似于"[^,\\s]+[^,]*[^,\\s]*")。
【解决方案3】:

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

【讨论】:

  • 错了。拆分删除所有最右边的空字符串,因此结果应该是一个空数组。看我的回答。 ",".split(",") 返回空数组。
【解决方案4】:

出于同样的原因

",test" split ','

",test," split ','

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

【讨论】:

  • @Nicklammort 这对我来说似乎是不言而喻的,但如果您需要更多信息,可以查看Stringsplit 的Javadocs。
  • @Raphael 或在 Oracle 数据库中
  • @Raphael,在任何其他编程语言中"".split("wtf").length 返回 0。仅在 JS 中为 1。:/
  • @DanielC.Sobral 好的,那为什么 "," split "," 返回一个 0 数组?
  • 为什么最后一场比赛之后的所有内容都没有返回?
【解决方案5】:

"a".split(",") -> "a" 所以 "".split(",") -> ""

【讨论】:

  • 错了。拆分删除所有最右边的空字符串,因此结果应该是一个空数组。看我的回答。 ",".split(",") 返回空数组。
【解决方案6】:

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

【讨论】:

  • 我认为这是一个库函数,而不是语言的一部分。例如,在 google guava 中,您可以省略空字符串。 >Iterable pieces = com.google.common.base.Splitter.on(',').omitEmptyStrings().split("");
【解决方案7】:

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

注意,你可以use the limit argument to modify the behavior:

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 行为似乎是众所周知的 quite confusing 但是:

至少从 Java 5 到 Java 8 都可以观察到上述行为。

JDK-6559590 中拆分空字符串时,尝试更改行为以返回空数组。但是,当它在各个地方引起回归时,它很快在JDK-8028321 中恢复。该更改从未进入 Java 8 的初始版本。

注意:split 方法从一开始就不是在 Java 中(它是 not in 1.0.2),但实际上至少从 1.4 开始就存在(例如,参见 JSR51 大约 2002 年)。我还在调查中……

不清楚的是为什么 Java 首先选择了它(我怀疑它最初是“边缘情况”中的疏忽/错误),但现在不可逆转地融入了语言中,所以 it remains

【讨论】:

  • 我不确定这是否能回答问题 - 虽然对于此处给出的示例可能是正确的,但它对空字符串的情况没有帮助 - "".split(",") 仍然返回一个元素数组,如[""]
  • @DaveyDaveDave 这是所有其他语言的预期行为。 ",,,," 是 Scala 中奇怪/不同的行为,与 "" 的情况不同。
【解决方案8】:

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

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

【讨论】:

    【解决方案9】:

    使用这个函数,

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-15
      • 2014-09-10
      • 2021-12-06
      • 2013-10-22
      相关资源
      最近更新 更多