String splitStr1 = "what,is,,,,";
String[] strs1 = splitStr1.split(",");
for (String s : strs1) {
System.out.println(s);
}
System.out.println(strs1.length);
System.out.println("==========>");
String splitStr2 = "what,is,,,,split";
String[] strs2 = splitStr2.split(",");
for (String s : strs2) {
System.out.println(s);
}
System.out.println(strs2.length);
what
is
2
==========>
what
is
split
6
对于出现这种情况当截取符号是最后一个时会去除掉空字符串,这点从源码即可看到。
public String[] split(String regex, int limit) {
/* 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.
*/
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))
{
int off = 0;
int next = 0;
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<>();
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
list.add(substring(off, value.length));
off = value.length;
break;
}
}
// If no match was found, return this
if (off == 0)
return new String[]{this};
// Add remaining segment
if (!limited || list.size() < limit)
list.add(substring(off, value.length));
// Construct result
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) {
resultSize--;
}
}
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}
让我们一行行开始解析
(regex.value.length == 1 && ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1)
regex.value.length == 1是为了排除多字符串,".$|()[{^?*+\"是排除这些特殊字符串,注意这里会给ch进行赋值。
(regex.length() == 2 && regex.charAt(0) == '\\' && (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 && ((ch-'a')|('z'-ch)) < 0 && ((ch-'A')|('Z'-ch)) < 0))
整个表达式的目的是确保 regex 是一个长度为 2 的字符串,并且它的第一个字符是反斜杠 \,第二个字符是一个数字字符、小写字母或大写字母。
1.regex.length() == 2: 这部分检查字符串 regex 的长度是否为 2。
2.regex.charAt(0) == ‘\’: 确保 regex 的第一个字符是反斜杠 \。
3.(((ch = regex.charAt(1))-‘0’)|(‘9’-ch)) < 0: 这段比较复杂。让我们分解一下:
3.1.ch = regex.charAt(1): 将 regex 的第二个字符赋值给变量 ch。
3.2.‘9’ - ch: 计算字符 ‘9’ 和 ch 之间的差值。
3.3.(ch - ‘0’): 计算字符 ch 和 ‘0’ 之间的差值。
3.4.((ch - ‘0’) | (‘9’ - ch)): 执行按位或操作。如果 ch 是一个数字字符(‘0’ 到 ‘9’ 之间),结果将 是一个负数。
3.5< 0: 确保结果是负数。
3.6所以这部分确保 regex 的第二个字符是一个数字字符(‘0’ 到 ‘9’ 之间的数字)。
(ch < Character.MIN_HIGH_SURROGATE || ch > Character.MAX_LOW_SURROGATE)
判断是否是两字节的unicode字符
while ((next = indexOf(ch, off)) != -1){}
if (off == 0)
return new String[]{this};
ch存的是ascall码当没有匹配的时候off为0,返回原值。
分析split方法:
方法的if判断内部,定义了off和next变量,作为拆分整个字符串的两个指针,然后limit作为拆分整个string字符串的一个阈值。在split()方法内部的复杂逻辑判断中,都围绕着这三个变量来进行。
由于regex为’,‘,所以满足if括号里的判断。一开始next和off指针都在0位置,limit为0,在while里的判断逻辑指的是获取’,'索引位置,由上图拆分的字符数组可知,next会分别为4,7,8,9,10。由于limited = limit > 0,得知limited为false,则逻辑会走到
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
}
进入第一次while循环体,此时的字符数组以及索引关系如下:
所以list集合里就会添加进字符串what。同理第二次进入while循环时,此时的字符数组以及索引关系如下:
list集合里就会添加进字符串is
第三次进入while循环时,此时的字符数组以及索引关系如下:
list集合里就会添加进空字符串""
第四次进入while循环时,此时的字符数组以及索引关系如下:
list集合里就会添加进空字符串""
当o指针指向位置10时,while((next = indexOf(ch, off)) != -1)结果为false,因为此时已经获取不到’,'了。
注意,此时list中包含的元素有:[what,is, , , ,]
if(!limited || list.size() < limit) {
list.add(substring(off, value.length);
}
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
resultSize--;
}
}
会将字符数组off(此时off为10)位置到value.length位置的字符串存进list集合里,也就是split元素,由于list集合最后一个元素为split,其大小不为0,所以就不会进行resultSize–。所以最终list集合里的元素就有6个元素,值为[what,is, , , ,split]。
对于String splitStr1 = “what,is,”;为什么length为2可以看下面代码就知道了:
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) {
resultSize--;
}
}
最后索引位置的list为空字符串,所以list.get(resultSize-1).length()为0,最终会将list中的空字符串给减少。
对于入参limit则可以总结为3点:
1.limit > 0,split()方法最多把字符串拆分成limit个部分。但是当limit为1的时候是原值返回
if (!limited || list.size() < limit - 1)
2.limit = 0,split()方法会拆分匹配到的最后一位regex。
3.limit < 0,split()方法会根据regex匹配到的最后一位,如果最后一位为regex,则多添加一位空字符串;如果不是则添加regex到字符串末尾的子字符串。
String splitStr1 = ",what,is,,,,split,";
String[] strs1 = splitStr1.split(",",-2);
for (String s : strs1) {
System.out.println(s);
}
System.out.println(strs1.length);
what
is
split
8