Java版本 1.8
背景
前端在传带分隔符的字符串参数时,由于前端处理失误,传了类似”a,b,c,,,”的字符串,后端接受后直接做了split(“,”)。由于没看文档,以为全部分割可以做判空处理,但是debnug的时候发现输出的结果是[“a”,”b”],所以重新看源码逻辑,标记注意事项。
测试用例
2.1 String.split(String regex)
String str=",a|1*b,2*|c,3*d|4,,,";
String[] split1 = str.split(",");
String[] split2=str.split("\|");
String[] split3=str.split(",|\|");
String[] split4=str.split("\d");
String[] split5=str.split("\*");
String[] split6=str.split("\d|\*");
String[] split7=str.split(",|a|\d|\*");
String[] split8=str.split("M");
System.out.println("------------------String.split(String regex)-----------------------");
System.out.println(JSON.toJSONString(split1));
System.out.println(JSON.toJSONString(split2));
System.out.println(JSON.toJSONString(split3));
System.out.println(JSON.toJSONString(split4));
System.out.println(JSON.toJSONString(split5));
//注意:如果多个分隔符邻近,分割后会出现空字符串的情况
System.out.println(JSON.toJSONString(split6));
System.out.println(JSON.toJSONString(split7));
System.out.println(JSON.toJSONString(split8));
2.1 String.split(String regex, int limit)
str=",a|1*b,2*|c,3*d|4,,,";
String[] split = str.split(",");
String[] split9 = str.split(",",-1);
String[] split10 = str.split(",",3);
System.out.println("------------------String.split(String regex, int limit)-----------------------");
System.out.println(JSON.toJSONString(split));
System.out.println(JSON.toJSONString(split9));
System.out.println(JSON.toJSONString(split10));
源码分析
由于String.split(String regex)就是调用String.split(String regex, int limit),看该函数就可以了。
从这里可以看到,如果字符串长度为1并且不为特殊字符或者长度为2并且第二个字符不为0-9a-zA-Z时就是字符串遍历,否则的话regex就是正则表达式,使用Pattern来解析分隔符(关于该部分的按下不表)。
回到相关代码逻辑:
当limit<=0时,由于!limited为true,会循环(!limited || list.size() < limit - 1)判断条件下的逻辑,整个字符串都进行分割完成。当limit>0时,由于!limited为flalse, 当list.size() < limit - 1就结束循环,并且将最后的字符子串加入list。这一步都会把空的字符串给加入到list中。
下一步时,判断如果limit==0,从尾部判断空字符串的长度来截取list返回。
limit的效果:
如果 limit > 0,(从左到右)最多分割 limit - 1 次,数组的长度将不会大于 limit ,结尾的空字符串不会丢弃。
如果 limit < 0,匹配到多少次就分割多少次,而且数组可以是任何长度。结尾的空字符串不会丢弃。
如果 limit = 0,匹配到多少次就分割多少次,数组可以是任何长度,并且结尾空字符串将被丢弃。
总结
通常情况下常用 String.split(String regex),但是该函数存在一些特殊逻辑,容易出现踩坑情况。还是需要了解源码逻辑,关注String.split(String regex, int limit) 的两个传参,regex如何去表示单个分隔字符串、多个分隔符、正则表达式和转义字符,limit则是对返回数据的影响。