String源码学习笔记-split

		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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值