为什么在空字符串上“拆分”会返回非空数组?


111

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

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

考虑这返回空数组:

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

请解释 :)


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

Answers:


37

出于同样的原因

",test" split ','

",test," split ','

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


5
空字符串是字符串,而不是没有。(除Excel以外的任何地方)
拉斐尔

5
@Raphael或在Oracle数据库中
奥斯汀,

7
@Raphael,在任何其他编程语言中均"".split("wtf").length返回0。仅在JS中为1::/
Andrey Mikhaylov-lolmaus 2014年

11
@ DanielC.Sobral好,那为什么"," split ","返回一个0数组呢?
2014年

5
为什么最后一场比赛之后的一切都还没有返回?
Didier A.

72

如果将橙子零次拆分,则只有一块-橙子。


8
但是橙色不是空的(idlu,如果这就是luluies的意思),而是橙色。也许拆分了一个应该存在但不存在的橙色,所以您获得了一个单一值:一个空白xD
Nick Rolando

8
这是一次深谈。

31
这个隐喻对有意义"orange".split(','),但显然与拆分空字符串无关。如果我将缺橙次数分成零次,则仍然没有橙。我们是将其表示为空的无橙列表,正好是一个无橙列表,十二个无橙列表还是什么?这不是我们最终得到什么的问题,而是我们如何表示它。
Matchu 2014年

1
但是,如果将不存在的书按书页分开,那么您将一无所获。
SMUsamaShah,

49

Java和Scala拆分方法按以下两个步骤操作:

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

据此,"".split(",")由于第二步,的结果应该是一个空数组,对吧?

这应该。不幸的是,这是人为引入的角壳。这是不好的,但至少它是记录java.util.regex.Pattern,如果你还记得看看文档,:

对于n == 0,结果与n <0相同,只是不返回结尾的空字符串。(请注意,如上所述,输入本身为空字符串的情况很特殊,并且limit参数不适用于该情况。)

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

因此,我建议您始终n == -1作为第二个参数传递(这将跳过上面的第二步),除非您特别知道要实现的目标/您确定空字符串不是您的程序将获得的输入内容。

解决方案2:使用Guava Splitter类

如果您已经在项目中使用Guava,则可以尝试Splitter(文档)类。它具有非常丰富的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
+1,这是唯一引用该文档并指出不一致的答案。但是,我没有在JavaDoc中找到注释的突出显示部分。
Yogu'8

我在java.util.regex.Pattern中找到了它,但是它似乎大部分都消失了。在撰写本文时,它肯定以javadoc的形式存在于官方OpenJDK源代码树中。 android.googlesource.com/platform/libcore / + / ... 也许我们应该报告错误?
拉克·克拉里

报告错误将是一个好主意-绝对不会改变其行为,但至少应将其记录在案。
Yogu

@RokKralj Android并未使用OpenJDK库,而是基于Apache Harmony,所以也许您在找错地方了?
lxgr

1
"".split (",", n)使用Oracle JDK 8为(-1,0,1)中的n生成一个单元素数组。很高兴只获得一个非空标记的列表-猜想可能需要一个完整的正则表达式(类似"[^,\\s]+[^,]*[^,\\s]*")。
simon.watts 18/09/17

40

拆分空字符串将空字符串作为第一个元素。如果在目标字符串中未找到定界符,则将获得一个大小为1的数组,该数组保留原始字符串,即使该字符串为空。


2
错误。拆分会删除所有最右边的空字符串,因此结果应该是一个空数组。看我的答案。 ",".split(",")返回空数组。
Rok Kralj

23

"a".split(",")-> "a" 因此 "".split(",")->""


6
错误。拆分会删除所有最右边的空字符串,因此结果应该是一个空数组。看我的答案。 ",".split(",")返回空数组。
Rok Kralj

5

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


我认为这是一个库函数,而不是语言的一部分。例如,在Google番石榴中,您可以省略空字符串。> Iterable <String>个= com.google.common.base.Splitter.on(',')。omitEmptyStrings()。split(“”);
oluies 2011年

2

不管split是好是坏,此行为都是从Java继承的
。Scala不会覆盖String原语中的定义。

注意,您可以使用limit参数来修改行为

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行为令人困惑,但是:

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

JDK-6559590中拆分空字符串时,尝试更改行为以返回空数组。但是,当它在各个地方引起回归时,很快就在JDK-8028321中对其进行了还原。所做的更改永远不会使它成为Java 8的初始发行版。

注意:split方法从一开始就不在Java中使用(不在1.0.2中),但实际上至少从1.4开始存在(例如,参见2002年的JSR51)。我仍在调查...

尚不清楚的是,为什么Java首先选择了此选项(我怀疑它最初是“边缘案例”中的一个疏忽/错误),但是现在不可撤销地融入了该语言,因此仍然存在


我不确定这是否能回答问题-虽然此处给出的示例可能是正确的,但对于空字符串的情况却无济于事- "".split(",")仍会返回单个元素数组,例如[""]
DaveyDaveDave

@DaveyDaveDave是所有其他语言的预期行为。“,”是Scala中的怪异/不同行为,与“”情况不同。
安迪·海登

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.