提到 Java 拆分字符串,我猜你十有八九会撂下一句狠话,“这有什么难的,直接上 String 类的 split() 方法不就拉到了!”假如你真的这么觉得,那可要注意了,事情远没这么简单。

来来来,搬个小板凳坐下。

假如现在有这样一串字符“沉默王二,一枚有趣的程序员”,需要按照中文的逗号“,”进行拆分,这意味着第一串字符为逗号前面的“沉默王二”,第二串字符为逗号后面的“一枚有趣的程序员”(这不废话)。另外,在拆分之前,要先进行检查,判断一下这串字符是否包含逗号,否则应该抛出异常。

public class Test {
    public static void main(String[] args) {
        String cmower = "沉默王二,一枚有趣的程序员";
        if (cmower.contains(",")) {
            String [] parts = cmower.split(",");
            System.out.println("第一部分:" + parts[0] +" 第二部分:" + parts[1]);
        } else {
            throw new IllegalArgumentException("当前字符串没有包含逗号");
        }
    }
}

这段代码看起来挺严谨的,对吧?程序输出的结果完全符合预期:

第一部分:沉默王二 第二部分:一枚有趣的程序员

这是建立在字符串是确定的情况下,最重要的是分隔符是确定的。否则,麻烦就来了。

大约有 12 种英文特殊符号,如果直接拿这些特殊符号替换上面代码中的分隔符(中文逗号),这段程序在运行的时候就会出现以下提到的错误。

  • 反斜杠 \(ArrayIndexOutOfBoundsException)
  • 插入符号 ^(同上)
  • 美元符号 $(同上)
  • 逗点 .(同上)
  • 竖线 |(正常,没有出错)
  • 问号 ?(PatternSyntaxException)
  • 星号 *(同上)
  • 加号 +(同上)
  • 左小括号或者右小括号 ()(同上)
  • 左方括号或者右方括号 [](同上)
  • 左大括号或者右大括号 {}(同上)

看到这,可能有小伙伴会说,“这不是钻牛角尖嘛”,不不不,做技术就应该秉持严谨的态度,否则,老大会给你的绩效打低分的——奖金拿得少,可不是好滋味。

那遇到特殊符号该怎么办呢?上正则表达式呗。

正则表达式是一组由字母和符号组成的特殊文本,它可以用来从文本中找出满足你想要的格式的句子。

那可能又有小伙伴说,“正则表达式那么多,我记不住啊!”别担心,我已经替你想好对策了。

下面这个链接是 GitHub 上学习正则表达式的一个在线文档,非常详细。遇到正则表达式的时候,掏出这份手册就完事了。记不住那么多正则表达式没关系啊,活学活用呗。

https://github.com/cdoco/learn-regex-zh

除了这份文档,还有一份:

https://github.com/cdoco/common-regex

作者收集了一些在平时项目开发中经常用到的正则表达式,可以直接拿来用,妙啊。

解决了心病之后,我们来用英文逗点“.”来替换一下分隔符:

String cmower = "沉默王二.一枚有趣的程序员";
if (cmower.contains(".")) {
    String [] parts = cmower.split("\\.");
    System.out.println("第一部分:" + parts[0] +" 第二部分:" + parts[1]);
}

在使用 split() 方法的时候,就需要使用正则表达式 \\. 来替代特殊字符英文逗点“.”了。为什么用两个反斜杠呢?因为它本身就是一个特殊字符,需要先转义。

也可以使用字符类 [] 来包含英文逗点“.”,它也是一个正则表达式,用来匹配方括号中包含的任意字符。

cmower.split("[.]");

除此之外, 还可以使用 Pattern 类的 quote() 方法来包裹英文逗点“.”,该方法会返回一个使用 \Q\E 包裹的字符串。

此时,String.split() 方法的使用示例如下所示:

String [] parts = cmower.split(Pattern.quote("."));

当通过调试模式进入 String.split() 方法源码的话,会发现以下细节:

return Pattern.compile(regex).split(this, limit);

String 类的 split() 方法调用了 Pattern 类的 split() 方法。也就意味着,我们拆分字符串有了新的选择,可以不使用 String 类的 split() 方法了。

public class TestPatternSplit {
    /**
     * 使用预编译功能,提高效率
     */
    private static Pattern twopart = Pattern.compile("\\.");

    public static void main(String[] args) {
        String [] parts = twopart.split("沉默王二.一枚有趣的程序员");
        System.out.println("第一部分:" + parts[0] +" 第二部分:" + parts[1]);
    }
}

除此之外,还可以使用 Pattern 配合 Matcher 类进行字符串拆分,这样做的好处是可以对要拆分的字符串进行一些严格的限制,来看一段示例代码:

public class TestPatternMatch {
    /**
     * 使用预编译功能,提高效率
     */
    private static Pattern twopart = Pattern.compile("(.+)\\.(.+)");

    public static void main(String[] args) {
        checkString("沉默王二.一枚有趣的程序员");
        checkString("沉默王二.");
        checkString(".一枚有趣的程序员");
    }

    private static void checkString(String str) {
        Matcher m = twopart.matcher(str);
        if (m.matches()) {
            System.out.println("第一部分:" + m.group(1) + " 第二部分:" + m.group(2));
        } else {
            System.out.println("不匹配");
        }
    }
}

这时候,正则表达式为 (.+)\\.(.+),意味着可以把字符串按照英文逗点拆分成一个字符组,英文小括号 () 的作用就在于此(可以查看我之前提供的正则表达式手册)。

由于模式是确定的,所以可以把 Pattern 表达式放在 main() 方法外面,通过 static 的预编译功能提高程序的效率。

来看一下程序的输出结果:

第一部分:沉默王二 第二部分:一枚有趣的程序员
不匹配
不匹配

不过,使用 Matcher 来匹配一些简单的字符串时相对比较沉重一些,使用 String 类的 split() 仍然是首选,因为该方法还有其他一些牛逼的功能。

比如说,你想把分隔符包裹在拆分后的字符串的第一部分,可以这样做:

String cmower = "沉默王二,一枚有趣的程序员";
if (cmower.contains(",")) {
    String [] parts = cmower.split("(?<=,)");
    System.out.println("第一部分:" + parts[0] +" 第二部分:" + parts[1]);
}

程序输出的结果如下所示:

第一部分:沉默王二, 第二部分:一枚有趣的程序员

可以看到分隔符“,”包裹在了第一部分,如果希望包裹在第二部分,可以这样做:

String [] parts = cmower.split("(?=,)");

可能有些小伙伴很好奇,?<=?= 是什么东东啊?它其实是正则表达式中的断言模式。

温馨提醒:如果对断言模式比较生疏的话,可以查看我之前提供的正则表达式手册。

另外,假如说字符串中包含了多个分隔符,而我们只需要 2 个的话,还可以这样做:

String cmower = "沉默王二,一枚有趣的程序员,宠爱他";
if (cmower.contains(",")) {
    String [] parts = cmower.split(",", 2);
    System.out.println("第一部分:" + parts[0] +" 第二部分:" + parts[1]);
}

split() 方法可以传递 2 个参数,第一个为分隔符,第二个为拆分的字符串个数。查看该方法源码的话,你就可以看到以下内容:

直接 substring() 到原字符串的末尾,也就是说,第二个分隔符处不再拆分。然后就 break 出循环了。来看一下程序输出的结果:

第一部分:沉默王二 第二部分:一枚有趣的程序员,宠爱他

好了,我亲爱的读者朋友,以上就是本文的全部内容了。是不是突然感觉拆分个字符串真的挺讲究的?

我是沉默王二,一枚有趣的程序员。如果觉得文章对你有点帮助,请微信搜索「 沉默王二 」第一时间阅读。

回复【666】更有我为你精心准备的 500G 高清教学视频(已分门别类)。本文 GitHub 已经收录,有大厂面试完整考点,欢迎 Star。

原创不易,莫要白票,请你为本文点赞个吧,这将是我写作更多优质文章的最强动力。

咦,Java拆分个字符串都这么讲究的更多相关文章

  1. java 中操作字符串都有哪些类?(未完成)它们之间有什么区别?(未完成)

    java 中操作字符串都有哪些类?(未完成)它们之间有什么区别?(未完成)

  2. LeetCode随缘刷题之Java经典面试题将一个字符串数组进行分组输出,每组中的字符串都由相同的字符组成

    今天给大家分享一个Java经典的面试题,题目是这样的: 本题是LeetCode题库中的49题. 将一个字符串数组进行分组输出,每组中的字符串都由相同的字符组成 举个例子:输入["eat&qu ...

  3. Java中的字符串

    Java语言中,把字符串作为对象来处理,类String就可以用来表示字符串(类名首字母都是大写的). 1.字符串常量 字符串常量是用双引号括住的一串字符. 例如:"Hello World&q ...

  4. java总结:字符串切割

    java中String.split()用法 在java.lang包中有String.split()方法,返回是一个数组.1.“.”和“|”都是转义字符,必须得加"\\"; 所以如果 ...

  5. Java编程基础-字符串

    在Java语言中,字符串数据实际上由String类所实现的.Java字符串类分为两类:一类是在程序中不会被改变长度的不变字符串:另一类是在程序中会被改变长度的可变字符串.Java环境为了存储和维护这两 ...

  6. Java学习:字符串概述与特点

    字符串概述与特点 java.lang.String类 代表字符串 API当中说:Java程序中的所有字符串字面值(如“abc“)都作为此类的实例实现.其实就是说:程序当中所用的双引号字符串,都是Str ...

  7. java中的字符串相关知识整理

    字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...

  8. 7.Java中的字符串

    1.String的特性 特性一:不可变性 String s=new String("yangyun") s=s.toUpperCase(); 这里的s,s占用的空间是不一样的(地址 ...

  9. Java六大问题你都懂了吗?

    这些问题对于认真学习java的人都要必知的,当然如果你只是初学者就没必要那么严格了,那如果你认为自己已经超越初学者了,却不很懂这些问题,请将你自己重归初学者行列. 一.到底要怎么样初始化! 本问题讨论 ...

随机推荐

  1. 死磕Lambda表达式(六):Consumer、Predicate、Function复合

    你的无畏来源于无知.--<三体> 在上一篇文章(传送门)中介绍了Comparator复合,这次我们来介绍一下其他的复合Lambda表达式. Consumer复合 Consumer接口中,有 ...

  2. 【原创】Linux RCU原理剖析(一)-初窥门径

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  3. mysql正则匹配中文时存在的问题

    可以看到,目前正则匹配字母没问题,c出现1次,2次,3次匹配的结果都是正常的 接下来我们看看匹配中文的效果 可以看到,当匹配连续出现歪时,结果就开始不正常了 然后我去看了下mysql的中文文档中关于正 ...

  4. 完整微信小程序授权登录页面教程

    完整微信小程序授权登录页面教程 1.前言 微信官方对getUserInfo接口做了修改,授权窗口无法直接弹出,而取而代之是需要创建一个button,将其open-type属性绑定getUseInfo方 ...

  5. npm install报错:chromedriver@2.27.2 install: node install.js

    报错: 刚开始以为是 node 或 npm 版本问题,前前后后折腾了好久,终于解决了 解决: 如果执行过npm install,先删除 node_modules 文件夹,不然运行的时候可能会报错 执行 ...

  6. JVM日常排查问题。基本操作和命令

    1.jstat jstat -gcutil pid 5s    //pid进程号 每隔5s监控一次内存回收情况 E 代表 Eden 区使用率:O(Old)代表老年代使用率    :P(Permanen ...

  7. C语言局部数组大小与内存的栈的关系

    今天有个同学问了一个问题,我居然答不上来,为什么不能开局部整型二维数组[1000][1000]?但是在数组前面加上一个static就可以了? windows下栈的大小(不是数据结构里面的栈)是2MB, ...

  8. leetcode c++做题思路和题解(2)——链表的例题和总结

    链表的例题和总结 0. 目录 环形链表 1. 环形链表 题目: https://leetcode-cn.com/problems/linked-list-cycle/ 看了别人的思路真是感概万千,思路 ...

  9. Bat 脚本学习 (基础篇)

    [转]Bat 脚本学习 2015-01-05 14:13 115人阅读 评论(0) 收藏 举报 基础部分: ============================================== ...

  10. Property [*****] not found on type [com.erp.pojo.ErpSupplier]

    我实体类里用的是 springboot 里@Slf4j   @Data  注解式写的  这样可以减少代码量 ,但是遇到一个问题影响我好长时间 出现了这个错误  Property [*****] not ...