咦,Java拆分个字符串都这么讲究

本文探讨了Java中使用String类的split()方法拆分字符串的常见问题,特别是在遇到特殊字符作为分隔符时的挑战。文章介绍了如何利用正则表达式解决这些问题,并提供了使用Pattern和Matcher类进行更复杂字符串拆分的示例。

提到 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。

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

<think>好的,我现在需要解决用户的问题:如何在Java中使用split方法拆分字符串时保留拆分的字符。用户可能遇到了拆分字符串但分隔符丢失的情况,想要保留这些分隔符。 首先,我得回忆一下JavaString类的split方法。默认情况下,split方法使用正则表达式作为参数,拆分后的结果数组不包含分隔符。例如,用逗号拆分"a,b,c",得到的是["a", "b", "c"],逗号不见了。 用户的需求是保留分隔符。这时候,可能需要用到正则表达式中的“零宽断言”(lookaround assertions)。因为split方法实际上是根据正则匹配的位置来拆分的,而零宽断言可以匹配位置而不消耗字符。 接下来,我需要确定如何构造这样的正则表达式。例如,如果想在每个逗号处拆分,但保留逗号,可以考虑两种方式:将逗号放在前面或后面的元素中。例如,拆分"a,b,c"为["a", ",b", ",c"]或者["a,", "b,", "c"],这取决于需求。 这时候,需要使用正向前瞻(positive lookahead)或者正向后顾(positive lookbehind)。例如,使用正向前瞻(?=,)表示在逗号前的位置拆分,这样逗号会保留在后面的部分。而使用正向后顾(?<=,)则表示在逗号后的位置拆分,逗号保留在前面的部分。 不过,split方法在匹配到这些位置时会进行拆分,但分隔符本身不会被包含在结果中,除非正则表达式中有捕获组。根据Java文档,如果正则表达式中有捕获组,那么匹配的组也会被包含在结果数组中。 所以可能需要调整正则表达式,使其包含捕获组来保留分隔符。例如,使用split("((?=,))"),这样每个逗号前的位置被匹配,并且作为捕获组,结果数组中会包含空字符串和逗号吗?这里可能需要测试一下。 或者,可能更有效的是使用split("(?=,)|(?<=,)"),这样在每个逗号的前后都拆分,从而将逗号作为单独的元素保留。例如,字符串"a,b,c"会被拆分为["a", ",", "b", ",", "c"]。这样可能更符合用户的需求。 但是用户可能希望将分隔符附加到前一个或后一个部分。例如,拆分成["a,", "b,", "c"]或者["a", ",b", ",c"]。这时候可能需要不同的正则处理。 比如,使用split("(?=,)")会使得在每个逗号前的位置拆分,这样拆分后的数组会是["a", ",b", ",c"]。而split("(?<=,)")会在每个逗号后拆分,得到["a,", "b,", "c"]。这时候分隔符被保留在相应的部分。 例如,测试字符串"a,b,c".split("(?=,)")得到的是["a", ",b", ",c"],而split("(?<=,)")得到["a,", "b,", "c"]。这可能就是用户所需要的。 另外,如果分隔符是多个字符或者更复杂的模式,可能需要调整正则表达式。比如,分隔符是分号或逗号,可以使用类似的正则表达式来处理。 总结一下,解决方案是使用正则表达式的零宽断言来指定拆分的位置,并且在需要的情况下结合捕获组,使得分隔符能够被保留在结果数组中。例如,使用正向前瞻或后顾来拆分,这样分隔符会被保留在拆分后的部分中。 需要提醒用户,不同的正则表达式写法会导致分隔符出现在不同位置,根据具体需求选择合适的方式。此外,注意处理可能出现的空字符串,尤其是在开头或结尾有分隔符的情况下,可能需要过滤掉空元素。</think>在Java中,使用`split()`方法拆分字符串时,默认会丢弃分隔符。若需保留分隔符,可通过正则表达式的**零宽断言(Lookaround Assertions)**实现。以下是两种常见场景的解决方案: --- ### 方法1:将分隔符保留在`后一段`字符串中 使用**正向前瞻**`(?=X)`,表示“匹配位置后必须跟着X”。 ```java String str = "a,b,c"; String[] parts = str.split("(?=,)"); // 在逗号前的位置拆分 // 结果:["a", ",b", ",c"] ``` --- ### 方法2:将分隔符保留在`前一段`字符串中 使用**正向后顾**`(?<=X)`,表示“匹配位置前必须有X”。 ```java String str = "a,b,c"; String[] parts = str.split("(?<=,)"); // 在逗号后的位置拆分 // 结果:["a,", "b,", "c"] ``` --- ### 复杂分隔符示例 若分隔符是`;`或`:`,可通过正则表达式组合处理: ```java String str = "a;b:c"; String[] parts = str.split("(?=;|:)|(?<=;|:)"); // 结果:["a", ";", "b", ":", "c"] ``` --- ### 注意事项 1. **空字符串问题** 若字符串开头/结尾有分隔符,结果可能包含空字符串。可用`filter`过滤: ```java String[] parts = str.split("(?=,)"); parts = Arrays.stream(parts).filter(s -> !s.isEmpty()).toArray(String[]::new); ``` 2. **特殊字符转义** 若分隔符含正则特殊字符(如`.`、`*`),需转义: ```java String str = "a.b*c"; String[] parts = str.split("(?=\\.|\\*)"); // 转义.和* ``` --- ### 原理说明 - **零宽断言**仅匹配位置,不消耗字符,因此分隔符不会被丢弃。 - `split()`根据匹配的`位置`拆分字符串,最终结果中会包含分隔符所在的段。 根据需求选择合适的方式,即可实现保留分隔符的字符串拆分
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉默王二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值