转载请标明出处:
原文首发于: http://www.zhangruibin.com
本文出自 RebornChang的博客
厚颜打广告,博主个人博客地址传送门 ,欢迎来访
split方法的分类
关于Java中的split方法,这里大致分为三种:
假定字符串String = “1,2,,,,,”,使用不同的split方法的话,其效果如下面所示;
js中的split方法
使用的方法:
var string = “1,2,,,,,”;
var arr = [];
arr = value.split(",");
alert(arr.length);
可以得到此时的arr数组的长度为6,也就是说,后面的那些逗号中间的空字符串,并没有trim掉;
Java中的使用方法
split(String regex)
String offerCodes = “1,2,,,,,”;
String[] offerCodeString = offerCodes.split(",");
System.out.println("offerCodeString.length"+offerCodeString.length);
控制台打印出来的数组长度为2;
可以看到,单参数,按照指定字符进行分割的话,后面的那些空字符串都默认去掉了,那如果我想要后面的这些空字符串怎么办?看下面的这种split方法;
split(Sting regex,int limit)
String offerCodes = “1,2,,,,,”;
String[] offerCodeString = offerCodes.split(",",-1);
System.out.println("offerCodeString.length"+offerCodeString.length);
控制台打印出来的数组长度为6;
也就是说没有把后面的空字符串去掉,但是为什么后面的参数填个-1呢?能不能换成其他的值?那这么想的话就有必要走一波源码了;
Java jdk1.8 split源码简析
源码注释
string字符串的split方法从JDK1.4中开始存在,来一波源码里面的表格:
源码中给出了示例字符串:“boo:and:foo”;然后,传入不同的参数,得到的结果如下:
Regex Limit Result : 2 "boo", "and:foo" : 5 "boo", "and", "foo" : -2 "boo", "and", "foo" o 5 "b", "", ":and:f", "", "" o -2 "b", "", ":and:f", "", "" o 0 "b", "", ":and:f"
split源码
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;
//这里是一堆的正则校验,大致是,传入的分割符是单符号位的,才进行下面的分割,否则,return Pattern.compile(regex).split(this, limit)调用另一个分割方法进行字符串分割位分割,文末会PO出此方法
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;
//从这里开始,进行limit值的入参及split逻辑
//当传进来的值是正数的时候,limit > 0 == true
boolean limited = limit > 0;
//声明一个list集合对返回值结果进行存储,用于最后给String[]赋值
ArrayList<String> list = new ArrayList<>();
//当没有按照指定的字符分割到最后一位的时候,执行while循环进行判断,然后使用substring(off, next)方法进行分割
while ((next = indexOf(ch, off)) != -1) {
//判断limited 为FALSE,即limit<0,或者,list.size() < limit - 1是否成立
if (!limited || list.size() < limit - 1) {
//若成立则使用substring(off, next)方法进行分割,并且加入到list中
list.add(substring(off, next));
//此时的初始标识符off为next+1
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
//不成立的话调用substring(off, value.length),此时value.length值为1
list.add(substring(off, value.length));
off = value.length;
break;
}
}
// 如果不符合,则返回 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).length() == 0) {
resultSize--;
}
}
//将所得到的list集合进行截取,使用toArray()方法赋值到String[] result中,所以这么看来,split方法的效率,是略差的
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}
总的来说:
limit 参数控制模式应用的次数,因此影响所得数组的长度。如果该限制 n 大于 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n ,而且数组的最后一项将包含所有超出最后匹配的定界符的输入。如果 n 为非正,那么模式将被应用尽可能多的次数,而且数组可以是任何长度。如果 n 为 0,那么模式将被应用尽可能多的次数,数组可以是任何长度,并且结尾空字符串将被丢弃。
下面的源码就不解析啦,有兴趣的看官可以自行查看:
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}