今天在项目对接时,对方对一个字符串使用小数点.来作为分隔符,使用String的split(".")方法处理出现了问题,阅读了一下String类的源码,发现了问题所在。
先举个列子看一下这个问题
String str = "xxx.yyy.zzz";
String[] strs = str.split(".");
System.out.println(strs.length);
运行结果 : 0;
来看看一下String源码中这个方法的实现
public String[] split(String regex) {
return split(regex, 0);
}
继续看split(regex, 0)这个两个参数的方法,我们先讨论第一个参数,String regex ,在源码中对这个参数是这样描述的
the delimiting regular expression
意思是分隔正则表达式,说明split分隔符是根据正则表达式匹配的,而不是简单的字符匹配,再来看方法的实现
char ch = 0;
if (((regex.value.length == 1 &&
".$|()[{^?*+\\".indexOf(ch = regex.charAt(0))
== -1) ||
(regex.length() == 2 &&
regex.charAt(0) == '\\' &&
(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0
&&
((ch-'a')|('z'-ch)) < 0 &&
((ch-'A')|('Z'-ch)) < 0)) &&
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE))
"\\.$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1)"
这个表达式的意思是要判断字符串".$|()[{^?*+\"中是否包含参数regex的第一位字符,方法中是希望不包含的,其实 . $ | ()…等这几个字符是正则表达式的特殊字符,都有确切含义,如果使用他们作为分隔符,是要进行转义的“\\.” “\\$” 以为\也是特殊字符,所以先对\转义,所以有两个\\。来试一下
String str = "xxx.yyy.zzz";
String[] strs = str.split("\\.");
System.out.println(strs.length);
运行结果 : 3
这里整个表达式的意思在源码里有说明如下
fastpath if the regex is a
(1)one-char String and this character is not one of the
RegEx’s meta characters “.$|()[{^?*+\”, or
(2)two-char String and the first char is the backslash and
the second is not the ascii digit or ascii letter.
意思字符长度为一的话那么这个字符不能是正则元字符.$|()[{^?*+\其中之一;
长度为二的话 那么第一个字符是反斜杠且第二个字符不是字母或数字;
试一下
String str = "xxx\\ayyy\\azzz";
System.out.println(str);
String[] strs1 = str.split("\\a");
String[] strs2 = str.split("\\\\a");
System.out.println(strs1.length);
System.out.println(strs2.length);
结果是 :
xxx\ayyy\azzz
1
3
下面来看第二个参数
* <p> The {@code limit} parameter controls the number of times the
* pattern is applied and therefore affects the length of the resulting
* array. If the limit <i>n</i> is greater than zero then the pattern
* will be applied at most <i>n</i> - 1 times, the array's
* length will be no greater than <i>n</i>, and the array's last entry
* will contain all input beyond the last matched delimiter. If <i>n</i>
* is non-positive then the pattern will be applied as many times as
* possible and the array can have any length. If <i>n</i> is zero then
* the pattern will be applied as many times as possible, the array can
* have any length, and trailing empty strings will be discarded.
源码中对这个参数的描述如上,意思是:
1.如果limit是一个正数,那么最多分个limit-1次,且分割之后的数组长度不会超过limit,数组的最后一个元素将包含最后一次分隔之后剩下的所有字符;
2.如果limit小于0,那么就会分隔尽可能多次
3.如果limit等于0,那么就会分隔尽可能多次,且结尾的空字符串将会被丢弃
至此,String的split用法已经很清晰了,当只有一个参数是,执行的是split(regex,0),当我们只需要截取恰面一部分上,就可以用到两个参数的split来进行截取;