20 May 2016

Java 字符串 API 有的接受普通文本,有的接受正则表达式。两者名称相近,参数含义却不同;使用 split 时尤其容易因为分隔符中的点号而得到意外结果。

contains 查文本,split 用正则

String value = "aaa.add.d";
System.out.println(value.contains("."));       // true
System.out.println(value.split(".").length);  // 0
System.out.println(value.split("\\.").length); // 3

这里展示 Java 源码时,最后一行的分隔参数应是 "\\.":字符串解析后得到反斜杠与点号,正则再把它解释为字面量点号。正则中的 . 匹配任意字符;split 又默认丢弃末尾空字符串,所以第二行长度为 0。

为避免手工处理转义,也可以使用 Pattern.quote:

String[] parts = value.split(java.util.regex.Pattern.quote("."));

是否保留空字段也要明确

System.out.println("a,b,".split(",").length);     // 2
System.out.println("a,b,".split(",", -1).length); // 3

负数 limit 保留末尾空字段,适合字段位置有含义的简单分隔文本。真正的 CSV 还涉及引号、转义和字段内换行,不能用一次 split 完整解析。

相似方法的区别

方法 参数含义
contains、startsWith、endsWith 字面文本
replace 字符或字面字符序列
matches、split 正则表达式;matches 要求整个字符串匹配
replaceAll、replaceFirst 查找参数为正则,替换参数也有特殊语法

替换字符串中的 $ 和反斜杠也可能被解释。如果替换内容来自外部输入,希望按普通文本使用,可以通过 Matcher.quoteReplacement 处理。选择 API 时先明确是否需要正则,通常比不断增加反斜杠更不容易出错。

参考:Java String、Pattern。





blog comments powered by Disqus
Fork me on GitHub