杰瑞科技汇

Java split分割字符串时如何处理特殊字符?

核心概念

String.split() 方法是一个实例方法,它根据一个正则表达式作为分隔符,将当前字符串分割成一个字符串数组。

方法签名:

public String[] split(String regex)

参数说明:

  • regex: 一个正则表达式,用作分割字符串的边界。特别注意,这里的参数是正则表达式,而不仅仅是普通字符。

返回值:

  • 一个字符串数组,数组中的每个元素都是原字符串被分割后的子字符串。

基本用法示例

示例 1:使用普通字符作为分隔符

当分隔符是简单的字符(如 , , ` `)时,用法非常直观。

public class SplitExample {
    public static void main(String[] args) {
        String sentence = "apple,banana,orange,grape";
        // 使用逗号 "," 作为分隔符
        String[] fruits = sentence.split(",");
        // 打印分割后的数组
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        // 输出:
        // apple
        // banana
        orange
        // grape
    }
}

示例 2:使用多个字符作为分隔符

分隔符也可以是多个字符。

public class SplitExample2 {
    public static void main(String[] args) {
        String text = "apple-and-banana-or-orange";
        // 使用 "and" 和 "or" 作为分隔符(这里需要用到正则表达式的或 "|")
        String[] items = text.split("and|or");
        for (String item : items) {
            System.out.println(item);
        }
        // 输出:
        // apple-
        // banana-
        // orange
    }
}

重要注意事项(陷阱)

陷阱 1:regex 参数是正则表达式

这是 split() 方法最常见的“坑”,如果你想在分隔符中使用一些在正则表达式中有特殊含义的字符,必须进行转义。

常见正则特殊字符: , , , , , , [, ], , , \, ^, ,

错误示例:

// 想要用 "." 分割 IP 地址,这是错误的!
String ip = "192.168.1.1";
String[] parts = ip.split("."); // 错误!
// 在正则中 "." 匹配的是任意字符,所以这会分割成 ["", "", "", "", "", "", "", ""]

正确示例: 必须使用反斜杠 \ 对 进行转义,在 Java 字符串中,反斜杠本身也需要转义,所以是 "\\."

String ip = "192.168.1.1";
// 必须对 "." 进行转义
String[] parts = ip.split("\\."); 
for (String part : parts) {
    System.out.println(part);
}
// 输出:
// 192
// 168
// 1
// 1

陷阱 2:分割结果中的空字符串

如果分隔符出现在字符串的开头、结尾或连续出现,split() 方法会产生空字符串 。

示例:

public class SplitEmptyExample {
    public static void main(String[] args) {
        String text1 = ",apple,orange,";
        String[] parts1 = text1.split(",");
        System.out.println("分割字符串: '" + text1 + "'");
        for (String part : parts1) {
            System.out.println("['" + part + "']"); // 用 [] 包裹,便于识别空字符串
        }
        // 输出:
        // 分割字符串: ',apple,orange,'
        // ['']      <- 开头的逗号产生了空字符串
        // ['apple']
        // ['orange']
        // ['']      <- 结尾的逗号产生了空字符串
        System.out.println("--------------------");
        String text2 = "a,,b,c";
        String[] parts2 = text2.split(",");
        System.out.println("分割字符串: '" + text2 + "'");
        for (String part : parts2) {
            System.out.println("['" + part + "']");
        }
        // 输出:
        // 分割字符串: 'a,,b,c'
        // ['a']
        // ['']      <- 连续的逗号产生了空字符串
        // ['b']
        // ['c']
    }
}

高级用法

重载方法:limit 参数

split() 方法还有一个重载版本,可以接收第二个参数 limit,用于控制分割的次数。

方法签名:

public String[] split(String regex, int limit)

limit 参数的作用:

  • limit > 0:分割最多 limit - 1 次,结果数组的长度将不会超过 limit
  • limit < 0:匹配模式将被应用尽可能多的次数,没有限制。
  • limit = 0:匹配模式将被应用尽可能多的次数,并且结果中不包含空字符串(这是与 limit < 0 的唯一区别)。

示例:

public class SplitLimitExample {
    public static void main(String[] args) {
        String text = "one,two,three,four,five";
        // limit = 2: 最多分割 1 次
        String[] parts1 = text.split(",", 2);
        System.out.println("limit = 2:");
        for (String part : parts1) {
            System.out.println("['" + part + "']");
        }
        // 输出:
        // ['one']
        // ['two,three,four,five']  <- 剩下的所有部分都在第二个元素里
        System.out.println("--------------------");
        // limit = 0: 移除末尾的空字符串
        String textWithEmptyEnd = "a,b,c,,";
        String[] parts2 = textWithEmptyEnd.split(",", 0);
        System.out.println("limit = 0 (移除末尾空字符串):");
        for (String part : parts2) {
            System.out.println("['" + part + "']");
        }
        // 输出:
        // ['a']
        // ['b']
        // ['c']
        // 注意:末尾的空字符串被移除了
    }
}

替代方案:StringTokenizer

虽然 split() 非常流行,但在某些场景下,java.util.StringTokenizer 类也是一个不错的选择。

split() 的主要区别:

  1. 性能StringTokenizer 通常比 split() 性能更好,因为它不使用正则表达式,解析速度更快,在需要处理大量数据且对性能要求极高的场景下,可以考虑它。
  2. 分隔符处理StringTokenizer 默认会跳过连续的分隔符,不会产生空字符串。"a,,b" 会被分割为 ["a", "b"]
  3. APIStringTokenizer 是一个迭代器风格的 API,通过 hasMoreTokens()nextToken() 方法来获取分割后的字符串。

示例:

import java.util.StringTokenizer;
public class StringTokenizerExample {
    public static void main(String[] args) {
        String text = "  apple, banana, , orange  ";
        // 创建 StringTokenizer,分隔符为逗号和空格
        // 注意:默认会跳过连续的分隔符,并且不会包含开头和结尾的空白
        StringTokenizer tokenizer = new StringTokenizer(text, ", ");
        System.out.println("使用 StringTokenizer:");
        while (tokenizer.hasMoreTokens()) {
            System.out.println("Token: [" + tokenizer.nextToken() + "]");
        }
        // 输出:
        // Token: [apple]
        // Token: [banana]
        // Token: [orange]
    }
}

总结与最佳实践

特性 String.split() StringTokenizer
分隔符 正则表达式 普通字符
空字符串 可能产生 默认跳过
性能 较慢(因正则) 较快
API 返回数组 迭代器风格
灵活性 极高,功能强大 一般,功能有限
适用场景 大多数常规情况,尤其是分隔符复杂或需要保留空字符串时 高性能要求的场景,分隔符简单且不需要空字符串

最佳实践建议:

  1. 首选 split():在绝大多数情况下,String.split() 是你的首选,它的代码更简洁,功能更强大,尤其是在处理复杂的分隔符逻辑时。
  2. 注意转义:永远记住 split() 的参数是正则表达式,如果分隔符是 , , 等特殊字符,一定要记得用 \\ 进行转义。
  3. 处理空字符串:明确你的业务逻辑是否需要处理由开头、结尾或连续分隔符产生的空字符串,如果不需要,可以考虑使用 split(regex, 0) 来自动移除它们。
  4. 性能瓶颈时考虑 StringTokenizer:如果你的代码性能分析显示 split() 是一个瓶颈,并且你的分隔符逻辑非常简单,那么可以尝试用 StringTokenizer 优化。
  5. 考虑 Java 8+ 的流式处理:如果你需要对分割后的结果进行进一步处理(如过滤、映射),结合 Java 8 的 Stream API 会非常方便。
// Java 8+ Stream API 示例
String text = "apple, banana, , orange";
Arrays.stream(text.split(","))  // 先分割
      .map(String::trim)       // 再修剪每个元素的空格
      .filter(s -> !s.isEmpty()) // 过滤掉空字符串
      .forEach(System.out::println);
// 输出:
// apple
// banana
// orange
分享:
扫描分享到社交APP
上一篇
下一篇