资讯专栏INFORMATION COLUMN

Split in Java

iOS122 / 2527人阅读

摘要:比如的结果是,长度为,因为首先匹配任意字符,所以原字符串中每一个都是分割符,这就产生了个空字符串,然后默认为,从后往前删除空字符串,结果就为空。

在 Java 中处理字符串时,split 是一个很常用的操作,但是这一简单的操作,却经常有意想不到的结果,就拿Guava库官方教程中的一个例子来说,",a,,b,".split(",") 的结果是?

1. "", "a", "", "b", ""
2. null, "a", null, "b", null
3. "a", null, "b"
4. "a", "b"
5. None of the above

正确答案应该是 5,以上都不对;正确结果是 ["", "a", "", "b"]

正是因为 JDK 自带的 split 这种奇怪的现象,其他开源库也都给出了自己的 split 方法,如 Apache Commons Lang 和上文中的 Guava 。

split in JDK8

String 类包含两个 split 重载方法,public String[] split(String regex)public String[] split(String regex, int limit),调用前者就相当于默认 limit = 0,而上面的例子中奇怪的现象就和这个 limit 有关。

JDK 文档中是这么解释的:

limitn 大于 0 时,会返回至多 n 项,最后一项会包含所有未被拆分的部分

n 小于 0 时,会返回所有拆分后的结果

n 等于 0 时,会返回所有拆分后的结果,但是最后跟着的空字符串会被删除

由于使用了单参数的 split 方法,n == 0,于是就产生了如上的结果。关于这一部分的 JDK 中的源码部分如下:

// Construct result
int resultSize = list.size();
if (limit == 0) {
    while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
        resultSize--;
    }
}

平常在分析一些具有固定格式的数据时,比如每一行都是 tab 分割的,且有固定列数,那么进行解析时可以使用 s.split(" ", -1) 来进行操作。这样会保存所有的分割项,包含任意部位的空字符串,比如

":a::b::".split(":", -1) => ["", "a", "", "b", "", ""]

另外一个需要注意的地方是,split 接收的参数是一个正则表达式,这一点经常容易忽略。比如 "a.b.c".split(".") 的结果是 [],长度为 0 ,因为首先 . 匹配任意字符,所以原字符串中每一个都是分割符,这就产生了 6 个空字符串, 然后 limit 默认为 0 ,从后往前删除空字符串,结果就为空。

split in Commons Lang

JDK 中的方法毕竟还是简单了一些,不能满足我们一些特殊需求,或者说不想使用正则,那么可以使用 Commons Lang 库中的方法。这些 split 方法有以下特点:

如果没有指定结果个数,都默认输出最多项

如果没有 PreserveAllTokens 后缀,默认将多个连续分割符视为 1 个,不保留任意位置空字符串

比如:

StringUtils.split("::a::b::", ":") => ["a", "b"]

需要注意的是 split(String str, String separatorChars) 方法中第二个参数的意义是每一个字符都被当成分割符,比如:

StringUtils.split(":a:b:", "ab") => [":", ":", ":"]

那么假如我想用 "ab" 整体作为分割符呢,可以使用 splitByWholeSeparator 方法:

StringUtils.splitByWholeSeparator("abcabc","ab") => ["c", "c"]

但这个方法有一个和其他方法表现不一致的地方,它保留了末尾的空字符串,且只保留一个。

StringUtils.splitByWholeSeparator("abb", "bb") => ["a", ""]
StringUtils.splitByWholeSeparator("bba", "bb") => ["a"]
StringUtils.splitByWholeSeparator("abbbbabbbb", "bb") =>["a", "a", ""]

另外一个我觉得很有用的就是一系列 splitPreserveAllTokens 重载函数了,因为默认输出所有结果,且保留了空字符串。和 JDK 中的 limit = -1 结果一致,但更易读一些。

split in Guava

假如你已经被上面这些特殊情况都绕晕了,不妨试试 Guava 库,它没有提供简单的一系列重载 split 方法,而是提供了一系列的工厂方法,采用链式调用,从而从方法名上就能看出结果,不用苦思冥想到底有没有陷阱。

Splitter.on(",")
        .trimResults(CharMatcher.is(","))
        .omitEmptyStrings()
        .limit(2)
        .split("a,,,,,b,,,,c,,,")
       
=> ["a", "b,,,,c"]

除了按照分割符外,还可以按照长度:

Splitter.fixedLength(3).split("abcde") => ["abc", "de"]

不像 JDK 和 Commons Lang 中的返回数组,Guava 返回 IterableList,而且这个 Iterable 已经重载了 toString,可以方便地进行打印测试。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68045.html

相关文章

  • python 历险记——一个 Java 程序员的告白(一)

    摘要:元组也支持内置函数的参数必须是一个序列字符串列表元组元组有什么用既然中有这么个数据结构,自然就有它的用武之地。 引言 想学爬虫还是 python 专业啊,之前一直在用 java, 现在决定尝尝鲜,使用 python及爬虫框架来完成网络数据采集。编程语言之间都是相通的,比如都需要模块化,引入其他文件来实现功能,使用列表等容器来处理数据,都要使用 json 或 xml 来解析和传输数据。你...

    leejan97 评论0 收藏0
  • python 历险记——一个 Java 程序员的告白(一)

    摘要:元组也支持内置函数的参数必须是一个序列字符串列表元组元组有什么用既然中有这么个数据结构,自然就有它的用武之地。 引言 想学爬虫还是 python 专业啊,之前一直在用 java, 现在决定尝尝鲜,使用 python及爬虫框架来完成网络数据采集。编程语言之间都是相通的,比如都需要模块化,引入其他文件来实现功能,使用列表等容器来处理数据,都要使用 json 或 xml 来解析和传输数据。你...

    newtrek 评论0 收藏0
  • Python基础之(二)字符串_列表_元组

    摘要:字符串在中,万物皆对象,显然字符串是对象类型,用表示。其二是声明为原始字符串如,由开头引起的字符串就是声明了后面引号里的东西是原始字符串,在里面放任何字符都表示该字符的原始含义,不需要再用转义符了。 Python字符串 在Python中,万物皆对象,显然字符串是对象类型,用str表示。字符串类型通常用单引号或者双引号包裹起来。 >>> Hello,world Hello,world >...

    asoren 评论0 收藏0
  • 如何用Python下载百度指数的数据

    摘要:大家好我是小小明,今天给大家演示如何使用直接采集百度指数的数据。本文不演示如何使用自动化工具采集百度指数,为了采集更简单将直接读取并解析接口。 大家好我是小小明,今...

    crossea 评论0 收藏0
  • 1034 有理数四则运算 (20 分)java

    摘要:本题要求编写程序,计算个有理数的和差积商。输出格式分别在行中按照有理数运算符有理数结果的格式顺序输出个有理数的和差积商。注意输出的每个有理数必须是该有理数的最简形式,其中是整数部分,是最简分数部分若为负数,则须加括号若除法分母为,则输出。 本题要求编写程序,计算 2 个有理数的和、差、积、商。 输入格式:输入在一行中按照 a1/b1 a2/b2 的格式给出两个分数形式的有理数,其中分...

    mikyou 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<