1. 概述

字符串操作是Java编程中的核心技能。常见任务之一是根据特定字符的最后一次出现分割字符串。

本教程将快速介绍两种实现方法。

2. 问题解析

目标是将字符串按指定字符的最后一次出现分割成两部分。通过示例可以快速理解:

给定输入字符串:

static final String INPUT1 = "a b c@e f g@x y z";

需要按最后一个 @ 分割,得到包含两个元素的字符串数组:

static final String[] EXPECTED1 = new String[] { "a b c@e f g", "x y z" };

⚠️ 注意:输入包含两个 @,但必须只按最后一个分割

特殊情况处理:

  1. 字符在开头:

    static final String INPUT2 = "@a b c";
    static final String[] EXPECTED2 = new String[] { "", "a b c" };
    
  2. 字符在结尾:

    static final String INPUT3 = "a b c@";
    static final String[] EXPECTED3 = new String[] { "a b c", "" };
    
  3. 不包含目标字符:

    static final String INPUT4 = "a b c";
    static final String[] EXPECTED4 = new String[] { "a b c" };
    

3. 使用 lastIndexOf() 方法

简单粗暴的方案:先找到目标字符最后出现的位置,再分割前后子串。

核心方法:

  • lastIndexOf():定位字符最后出现位置
  • substring():截取子串

初始实现:

String[] splitByLastOccurrence(String input, char character) {
    int idx = input.lastIndexOf(character);
    return new String[] { input.substring(0, idx), input.substring(idx + 1) };
}

❌ 踩坑:当输入不包含目标字符(如INPUT4)时,idx = -1substring(0, -1) 会抛出异常。

修复方案:

String[] splitByLastOccurrence(String input, char character) {
    int idx = input.lastIndexOf(character);
    if (idx < 0) {
        return new String[] { input };
    }
    return new String[] { input.substring(0, idx), input.substring(idx + 1) };
}

✅ 验证测试:

String[] result1 = splitByLastOccurrence(INPUT1, '@');
assertArrayEquals(EXPECTED1, result1);
 
String[] result2 = splitByLastOccurrence(INPUT2, '@');
assertArrayEquals(EXPECTED2, result2);
 
String[] result3 = splitByLastOccurrence(INPUT3, '@');
assertArrayEquals(EXPECTED3, result3);
 
String[] result4 = splitByLastOccurrence(INPUT4, '@');
assertArrayEquals(EXPECTED4, result4);

4. 使用 split() 方法

利用正则表达式匹配最后一个目标字符:

关键正则:@(?=[^@]*$)
解释:正向预查确保匹配的 @ 后面没有其他 @ 字符。

初始尝试:

String regex = "@(?=[^@]*$)";
 
String[] result1 = INPUT1.split(regex);
assertArrayEquals(EXPECTED1, result1);
 
String[] result2 = INPUT2.split(regex);
assertArrayEquals(EXPECTED2, result2);
 
String[] result3 = INPUT3.split(regex);
assertArrayEquals(new String[] { "a b c d" }, result3); // ❌ 失败
 
String[] result4 = INPUT4.split(regex);
assertArrayEquals(EXPECTED4, result4);

⚠️ 问题:split() 默认丢弃尾部空字符串(如INPUT3的 "" 被丢弃)。

解决方案:指定 limit=2 限制分割次数:

String regex = "@(?=[^@]*$)";
 
String[] result1 = INPUT1.split(regex, 2);
assertArrayEquals(EXPECTED1, result1);
 
String[] result2 = INPUT2.split(regex, 2);
assertArrayEquals(EXPECTED2, result2);
 
String[] result3 = INPUT3.split(regex, 2);
assertArrayEquals(EXPECTED3, result3);
 
String[] result4 = INPUT4.split(regex, 2);
assertArrayEquals(EXPECTED4, result4);

5. 总结

本文通过示例介绍了两种按字符最后出现分割字符串的方法:

方法 优点 缺点
lastIndexOf() 逻辑直观 需手动处理边界情况
split() 代码简洁 需理解正则表达式

两种方法都能有效处理各种场景,可根据实际需求选择。

完整示例代码见 GitHub仓库


原始标题:Split a String Based on the Last Occurrence of a Character | Baeldung